From 916138b8df20f2386a1f70fcb80b66911976c9c1 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 9 May 2023 18:53:08 +0000 Subject: [PATCH 001/320] 12.0.0 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 33b27c6ab9a..79355b2c4c9 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "11.30.0", + "version": "12.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "11.30.0", + "version": "12.0.0", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index e659354e6ef..af20fa2f39a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "11.30.0", + "version": "12.0.0", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From 2e84e941339b33f4ab512d46161a4383e29a6222 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 9 May 2023 18:53:20 +0000 Subject: [PATCH 002/320] [firebase-release] Removed change log and reset repo after 12.0.0 release --- CHANGELOG.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19117d96e9f..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +0,0 @@ -- Adds `ext:dev:*` commands to publish and manage Extensions. For step-by-step instructions on how to publish your own Extensions, see https://firebase.google.com/docs/extensions/publishers/get-started. - - Note: These commands were previously available to early access users behind an experiment flag. There are some breaking changes from the early access version of these commands. - - `ext:dev:publish` has been renamed to `ext:dev:upload`. `ext:dev:upload` defaults to uploading extensions from GitHub instead of local source. - - `ext:dev:publish` is deprecated and will be removed in version 13. - - `ext:dev:delete`, `ext:dev:unpublish`, `ext:sources:create` and `ext:dev:emualtors:*` have been removed. -- Support for Next.js i18n, basePath, and more advanced rewrites/redirects/headers (#5788) -- hosting.frameworksBackend now respects omit: true (#5788) -- Web Frameworks now memoizes framework builds for single builds across multiple hosting sites (#5788) -- Add support for Angular i18n and baseHref (#5774) -- Trip the backend requirement for Angular applications using ng-deploy w/serveOptimizedImages (#5774) -- Fixes a bug where the Storage emulator would not fall back to open rules for 'demo-' projects if `firebase.json` contained multiple storage targets (#5170) -- Updates `firebase init` function templates for TypeScript and Javascript to 2nd gen (#5775) -- Allow for atomic deployment of Hosting content & Functions rewrites via tag pinning (#5753) From f8f19dc060e6daf060b87d38fd2a38d24bab8210 Mon Sep 17 00:00:00 2001 From: joehan Date: Thu, 11 May 2023 13:06:17 -0700 Subject: [PATCH 003/320] Correctly handle optional fields in EventArc emulator (#5819) * Optional attributes shoud actually be optional * add changelog * Fix tests * Actually fix tests --- CHANGELOG.md | 1 + src/emulator/eventarcEmulatorUtils.ts | 4 +-- .../emulators/eventarcEmulatorUtils.spec.ts | 36 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..07cf7f67137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Fixes an issue in the EventArc emualtor where events missing optional fields would cause crashes. (#5803) diff --git a/src/emulator/eventarcEmulatorUtils.ts b/src/emulator/eventarcEmulatorUtils.ts index 3cc06f5a539..4b3b631c62b 100644 --- a/src/emulator/eventarcEmulatorUtils.ts +++ b/src/emulator/eventarcEmulatorUtils.ts @@ -36,11 +36,11 @@ export function cloudEventFromProtoToJson(ce: any): CloudEvent { } function getOptionalAttribute(ce: any, attr: string, type: string): string | undefined { - return ce["attributes"][attr][type]; + return ce?.["attributes"]?.[attr]?.[type]; } function getRequiredAttribute(ce: any, attr: string, type: string): string { - const val = ce["attributes"][attr][type]; + const val = ce?.["attributes"]?.[attr]?.[type]; if (val === undefined) { throw new FirebaseError("CloudEvent must contain " + attr + " attribute"); } diff --git a/src/test/emulators/eventarcEmulatorUtils.spec.ts b/src/test/emulators/eventarcEmulatorUtils.spec.ts index d7015a11829..d58557f5cb4 100644 --- a/src/test/emulators/eventarcEmulatorUtils.spec.ts +++ b/src/test/emulators/eventarcEmulatorUtils.spec.ts @@ -122,5 +122,41 @@ describe("eventarcEmulatorUtils", () => { expect(got.datacontenttype).to.deep.eq("text/plain"); expect(got.data).to.eq("hello world"); }); + + it("allows optional attribute to not be set", () => { + expect( + cloudEventFromProtoToJson({ + "@type": "type.googleapis.com/io.cloudevents.v1.CloudEvent", + attributes: { + customattr: { + ceString: "custom value", + }, + datacontenttype: { + ceString: "application/json", + }, + time: { + ceTimestamp: "2022-03-16T20:20:42.212Z", + }, + }, + id: "user-provided-id", + source: "/my/functions", + specVersion: "1.0", + textData: '{"hello":"world"}', + type: "some.custom.event", + }) + ).to.deep.eq({ + type: "some.custom.event", + specversion: "1.0", + datacontenttype: "application/json", + id: "user-provided-id", + subject: undefined, + data: { + hello: "world", + }, + source: "/my/functions", + time: "2022-03-16T20:20:42.212Z", + customattr: "custom value", + }); + }); }); }); From 56fb8a34201ab903f92178f696bc3b28acfb79bb Mon Sep 17 00:00:00 2001 From: aalej Date: Fri, 12 May 2023 23:54:31 +0800 Subject: [PATCH 004/320] Fix Python Functions error when path has spaces (#5831) Proposed fix for #5830 Issue seems to be caused by [spawn](https://github.com/firebase/firebase-tools/blob/f8f19dc060e6daf060b87d38fd2a38d24bab8210/src/functions/python.ts#L38) raising an error when path provided has spaces. Might be related to https://github.com/nodejs/node/issues/38490. ### Scenarios Tested Similar to steps provided in #5830 1. Run `mkdir 'i like spaces'` 2. Run `cd i\ like\ spaces` or `cd 'i like spaces'` 3. Run `firebase init functions --project ` 1. Select `Python` 2. Do you want to install dependencies now? Yes 4. Run `cd functions` 5. Run `firebase emulators:start` 1. Emulators start with no issues 7. Uncomment code in `main.py` to deploy 8. Run `firebase deploy --only functions` 1. Functions deployed with no issues ### Sample Commands `firebase emulators:start` && `firebase deploy --only functions` --- CHANGELOG.md | 1 + src/functions/python.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07cf7f67137..80cf100d315 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Fixes an issue in the EventArc emualtor where events missing optional fields would cause crashes. (#5803) +- Fixes an issue running `firebase emulators:start` and `firebase deploy` when Python Cloud Functions directory path has spaces. (#5830) diff --git a/src/functions/python.ts b/src/functions/python.ts index 206cf289e65..5d51124b92d 100644 --- a/src/functions/python.ts +++ b/src/functions/python.ts @@ -14,7 +14,7 @@ export const DEFAULT_VENV_DIR = "venv"; export function virtualEnvCmd(cwd: string, venvDir: string): { command: string; args: string[] } { const activateScriptPath = process.platform === "win32" ? ["Scripts", "activate.bat"] : ["bin", "activate"]; - const venvActivate = path.join(cwd, venvDir, ...activateScriptPath); + const venvActivate = `"${path.join(cwd, venvDir, ...activateScriptPath)}"`; return { command: process.platform === "win32" ? venvActivate : ".", args: [process.platform === "win32" ? "" : venvActivate], From aa253a24805f09e7d59f35015772d0abb5efe94c Mon Sep 17 00:00:00 2001 From: Bryan Kendall Date: Tue, 16 May 2023 11:55:02 -0500 Subject: [PATCH 005/320] upgrade vm2 (#5844) --- npm-shrinkwrap.json | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 79355b2c4c9..17e6b5fbaf2 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -18594,8 +18594,9 @@ } }, "node_modules/vm2": { - "version": "3.9.17", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.17.tgz", + "version": "3.9.19", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", + "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", "dependencies": { "acorn": "^8.7.0", "acorn-walk": "^8.2.0" @@ -33107,8 +33108,9 @@ "requires": {} }, "vm2": { - "version": "3.9.17", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.17.tgz", + "version": "3.9.19", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", + "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", "requires": { "acorn": "^8.7.0", "acorn-walk": "^8.2.0" From d6f6da4378052581ecca0a95a419cb72010b6dca Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 16 May 2023 19:41:52 +0000 Subject: [PATCH 006/320] 12.0.1 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 17e6b5fbaf2..1a79a90c491 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.0.0", + "version": "12.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.0.0", + "version": "12.0.1", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index af20fa2f39a..21bee0bc4ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.0.0", + "version": "12.0.1", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From b0b6797198d3e6fde8631a03d234a31dcf3b3f3d Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 16 May 2023 19:42:05 +0000 Subject: [PATCH 007/320] [firebase-release] Removed change log and reset repo after 12.0.1 release --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80cf100d315..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +0,0 @@ -- Fixes an issue in the EventArc emualtor where events missing optional fields would cause crashes. (#5803) -- Fixes an issue running `firebase emulators:start` and `firebase deploy` when Python Cloud Functions directory path has spaces. (#5830) From 60b91bdcb2f86e98f8986f57cd2ad17a1b9f5573 Mon Sep 17 00:00:00 2001 From: aalej Date: Thu, 18 May 2023 07:30:29 +0800 Subject: [PATCH 008/320] Fix issue with Python Functions when path has spaces (#5858) ### Description Proposed fix for #5854. Related to #5830. Issue seems to be similar as the error message shows the incomplete path when path has spaces. e.g. if path is `/Users//Desktop/project directory/function`, error message will shows path `/Users//Desktop/project`. ### Scenarios Tested 1. Create a directory with a space 2. Run `firebase init functions` and run through the setup for Python functions. 3. Run `firebase init emulators` and setup the functions emulator 4. Run `firebase emulators:start` ### Sample Commands `firebase emulators:start` --- CHANGELOG.md | 1 + src/deploy/functions/runtimes/python/index.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..646920c6932 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Fixes an issue running `firebase emulators:start` when Python Cloud Functions directory path has spaces. (#5854) diff --git a/src/deploy/functions/runtimes/python/index.ts b/src/deploy/functions/runtimes/python/index.ts index 7a9af032b68..e17a9043539 100644 --- a/src/deploy/functions/runtimes/python/index.ts +++ b/src/deploy/functions/runtimes/python/index.ts @@ -144,7 +144,7 @@ export class Delegate implements runtimes.RuntimeDelegate { ...envs, ADMIN_PORT: port.toString(), }; - const args = [this.bin, path.join(modulesDir, "private", "serving.py")]; + const args = [this.bin, `"${path.join(modulesDir, "private", "serving.py")}"`]; const stdout: string[] = []; const stderr: string[] = []; logger.debug( From d34b67444aded22f7df8cc6e08da620898ba2d20 Mon Sep 17 00:00:00 2001 From: mojh7 Date: Thu, 18 May 2023 08:45:05 +0900 Subject: [PATCH 009/320] Fix typo in utils.ts (#5829) Co-authored-by: Daniel Lee --- src/frameworks/angular/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frameworks/angular/utils.ts b/src/frameworks/angular/utils.ts index 9026e80f408..7581cd2b3e0 100644 --- a/src/frameworks/angular/utils.ts +++ b/src/frameworks/angular/utils.ts @@ -143,7 +143,7 @@ export async function getContext(dir: string) { ? "production" : target.defaultConfiguration; if (!configuration) - throw new Error("No production or default configutation found for prerender."); + throw new Error("No production or default configuration found for prerender."); if (configuration !== "production") console.warn( `Using ${configuration} configuration for the prerender, we suggest adding a production target.` @@ -164,7 +164,7 @@ export async function getContext(dir: string) { ? "production" : target.defaultConfiguration; if (!configuration) - throw new Error("No production or default configutation found for build."); + throw new Error("No production or default configuration found for build."); if (configuration !== "production") console.warn( `Using ${configuration} configuration for the browser deploy, we suggest adding a production target.` From 3ff79943e15fc41f0c0c1a99a58c0080bf1de7ef Mon Sep 17 00:00:00 2001 From: Will Battel Date: Thu, 18 May 2023 08:45:40 -0400 Subject: [PATCH 010/320] Add support for nodejs20 (in preview) (#5837) --- CHANGELOG.md | 1 + schema/firebase-config.json | 6 ++++-- src/deploy/functions/runtimes/index.ts | 2 ++ .../functions/runtimes/node/parseRuntimeAndValidateSDK.ts | 1 + src/firebaseConfig.ts | 8 +++++++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 646920c6932..eb55b19136f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Fixes an issue running `firebase emulators:start` when Python Cloud Functions directory path has spaces. (#5854) +- Add support for nodejs20 for Cloud Functions for Firebase. (#5837) diff --git a/schema/firebase-config.json b/schema/firebase-config.json index 0d7d3010abe..ca1f66754b1 100644 --- a/schema/firebase-config.json +++ b/schema/firebase-config.json @@ -617,7 +617,8 @@ "nodejs12", "nodejs14", "nodejs16", - "nodejs18" + "nodejs18", + "nodejs20" ], "type": "string" }, @@ -672,7 +673,8 @@ "nodejs12", "nodejs14", "nodejs16", - "nodejs18" + "nodejs18", + "nodejs20" ], "type": "string" }, diff --git a/src/deploy/functions/runtimes/index.ts b/src/deploy/functions/runtimes/index.ts index d51dd2041af..8e0464a95c5 100644 --- a/src/deploy/functions/runtimes/index.ts +++ b/src/deploy/functions/runtimes/index.ts @@ -12,6 +12,7 @@ const RUNTIMES: string[] = [ "nodejs14", "nodejs16", "nodejs18", + "nodejs20", "python310", "python311", ]; @@ -43,6 +44,7 @@ const MESSAGE_FRIENDLY_RUNTIMES: Record = { nodejs14: "Node.js 14", nodejs16: "Node.js 16", nodejs18: "Node.js 18", + nodejs20: "Node.js 20", python310: "Python 3.10", python311: "Python 3.11", }; diff --git a/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts b/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts index 379e8c8b790..4ce21970fa8 100644 --- a/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts +++ b/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts @@ -17,6 +17,7 @@ const ENGINE_RUNTIMES: Record Date: Fri, 19 May 2023 14:26:20 -0400 Subject: [PATCH 011/320] Add init support for Flutter web (#5864) * Add init support for Flutter Web * cross-spawn was returning status undefined, handle * Add docs for Flutter Web * Fix doc up a bit --- CHANGELOG.md | 2 + src/frameworks/angular/index.ts | 4 +- src/frameworks/astro/index.ts | 2 +- src/frameworks/docs/angular.md | 4 +- src/frameworks/docs/express.md | 4 +- src/frameworks/docs/flutter.md | 46 ++++++++++++++ src/frameworks/docs/frameworks-overview.md | 8 ++- src/frameworks/docs/nextjs.md | 4 +- src/frameworks/flutter/constants.ts | 71 ++++++++++++++++++++++ src/frameworks/flutter/index.ts | 32 +++++++++- src/frameworks/flutter/utils.ts | 5 +- src/frameworks/index.ts | 2 +- src/frameworks/next/index.ts | 2 +- src/test/frameworks/astro/index.spec.ts | 39 ++++++------ src/test/frameworks/flutter/index.spec.ts | 64 ++++++++++++++++--- src/test/frameworks/flutter/utils.spec.ts | 16 +++-- 16 files changed, 252 insertions(+), 53 deletions(-) create mode 100644 src/frameworks/docs/flutter.md create mode 100644 src/frameworks/flutter/constants.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index eb55b19136f..55aae1b1536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,4 @@ - Fixes an issue running `firebase emulators:start` when Python Cloud Functions directory path has spaces. (#5854) - Add support for nodejs20 for Cloud Functions for Firebase. (#5837) +- Add Flutter Web as an option in "firebase init hosting" (#5864) +- Some failures while building Web Frameworks were not being caught (#5864) diff --git a/src/frameworks/angular/index.ts b/src/frameworks/angular/index.ts index 43f8a6500b4..1c92924fd3c 100644 --- a/src/frameworks/angular/index.ts +++ b/src/frameworks/angular/index.ts @@ -15,6 +15,7 @@ import { } from "../utils"; import { getBrowserConfig, getBuildConfig, getContext, getServerConfig } from "./utils"; import { I18N_ROOT, SHARP_VERSION } from "../constants"; +import { FirebaseError } from "../../error"; export const name = "Angular"; export const support = SupportLevel.Preview; @@ -58,10 +59,11 @@ export async function build(dir: string): Promise { // TODO there is a bug here. Spawn for now. // await scheduleTarget(prerenderTarget); const cli = getNodeModuleBin("ng", dir); - spawnSync(cli, ["run", target], { + const result = spawnSync(cli, ["run", target], { cwd: dir, stdio: "inherit", }); + if (result.status !== 0) throw new FirebaseError(`Unable to build ${target}`); } const wantsBackend = !!serverTarget || serveOptimizedImages; const i18n = !!locales; diff --git a/src/frameworks/astro/index.ts b/src/frameworks/astro/index.ts index 9ed53d61b7c..76481ca61d0 100644 --- a/src/frameworks/astro/index.ts +++ b/src/frameworks/astro/index.ts @@ -42,7 +42,7 @@ export async function build(cwd: string): Promise { ); } const build = spawnSync(cli, ["build"], { cwd, stdio: "inherit" }); - if (build.status) throw new FirebaseError("Unable to build your Astro app"); + if (build.status !== 0) throw new FirebaseError("Unable to build your Astro app"); return { wantsBackend: output === "server" }; } diff --git a/src/frameworks/docs/angular.md b/src/frameworks/docs/angular.md index 6cbc3358898..2b6c84ecafa 100644 --- a/src/frameworks/docs/angular.md +++ b/src/frameworks/docs/angular.md @@ -21,9 +21,9 @@ to Firebase and serve dynamic content to your users. <<_includes/_initialize-firebase.md>> +1. Answer yes to "Do you want to use a web framework? (experimental)" 1. Choose your hosting source directory; this could be an existing Angular app. -1. Choose "Dynamic web hosting with web framework." -1. Choose Angular. +1. If prompted, choose Angular. ### Initialize an existing project diff --git a/src/frameworks/docs/express.md b/src/frameworks/docs/express.md index b0d4cb9929a..dbd49e78f4e 100644 --- a/src/frameworks/docs/express.md +++ b/src/frameworks/docs/express.md @@ -23,9 +23,9 @@ to extend integration support to frameworks other than Angular and Next.js. <<_includes/_initialize-firebase.md>> +1. Answer yes to "Do you want to use a web framework? (experimental)" 1. Choose your hosting source directory; this could be an existing web app. -1. Choose "Dynamic web hosting with web framework." -1. Choose Express.js / custom +1. If prompted, choose Express.js / custom ### Initialize an existing project diff --git a/src/frameworks/docs/flutter.md b/src/frameworks/docs/flutter.md new file mode 100644 index 00000000000..cde055c7ee9 --- /dev/null +++ b/src/frameworks/docs/flutter.md @@ -0,0 +1,46 @@ +Project: /docs/hosting/_project.yaml +Book: /docs/_book.yaml +page_type: guide + +{% include "_shared/apis/console/_local_variables.html" %} +{% include "_local_variables.html" %} +{% include "docs/hosting/_local_variables.html" %} + + + +# Integrate Flutter Web + +With the Firebase framework-aware {{cli}}, you can deploy your Flutter application +to Firebase and serve dynamic content to your users. + +<<_includes/_preview-disclaimer.md>> + +<<_includes/_before-you-begin.md>> + +<<_includes/_initialize-firebase.md>> + +1. Answer yes to "Do you want to use a web framework? (experimental)" +1. Choose your hosting source directory; this could be an existing Flutter app. +1. If prompted, choose Flutter Web. + +### Initialize an existing project + +Change your hosting config in `firebase.json` to have a `source` option, rather +than a `public` option. For example: + +```json +{ + "hosting": { + "source": "./path-to-your-flutter-app" + } +} +``` + +## Serve static content + +After initializing Firebase, you can serve static content with the standard +deployment command: + +```shell +firebase deploy +``` diff --git a/src/frameworks/docs/frameworks-overview.md b/src/frameworks/docs/frameworks-overview.md index 36bc7f83b58..351ab5010b4 100644 --- a/src/frameworks/docs/frameworks-overview.md +++ b/src/frameworks/docs/frameworks-overview.md @@ -14,6 +14,11 @@ page_type: guide and Next.js. Using {{firebase_hosting}} and {{cloud_functions_full}} with these frameworks, you can develop apps and microservices in your preferred framework environment, and then deploy them in a managed, secure server environment. + +Note: Experimental support for Flask and Django is under development, and will be +available soon. To stay up to date on the latest releases, sign up as a +trusted tester at [https://goo.gle/41enW5X](//goo.gle/41enW5X). + Support during this early preview includes the following functionality: * Deploy Web apps comprised of static web content @@ -51,4 +56,5 @@ See the detailed guide for your preferred framework: * [Angular Universal](/docs/hosting/frameworks/angular) * [Next.js] (/docs/hosting/frameworks/nextjs) -* [Frameworks with Express.js](/docs/hosting/frameworks/ßexpress) +* [Flutter Web] (/docs/hosting/frameworks/flutter) +* [Frameworks with Express.js](/docs/hosting/frameworks/express) diff --git a/src/frameworks/docs/nextjs.md b/src/frameworks/docs/nextjs.md index 7a14e0d6147..4f8f5e4e65d 100644 --- a/src/frameworks/docs/nextjs.md +++ b/src/frameworks/docs/nextjs.md @@ -27,10 +27,10 @@ logic to {{cloud_functions_full}}. <<_includes/_initialize-firebase.md>> +1. Answer yes to "Do you want to use a web framework? (experimental)" 1. Choose your hosting source directory. If this an existing Next.js app, the {{cli}} process completes, and you can proceed to the next section. -1. Choose "Dynamic web hosting with web framework" -1. Choose Next.js. +1. If prompted, choose Next.js. ## Serve static content diff --git a/src/frameworks/flutter/constants.ts b/src/frameworks/flutter/constants.ts new file mode 100644 index 00000000000..7381c0d9682 --- /dev/null +++ b/src/frameworks/flutter/constants.ts @@ -0,0 +1,71 @@ +// https://dart.dev/language/keywords +export const DART_RESERVED_WORDS = [ + "abstract", + "else", + "import", + "show", + "as", + "enum", + "in", + "static", + "assert", + "export", + "interface", + "super", + "async", + "extends", + "is", + "switch", + "await", + "extension", + "late", + "sync", + "base", + "external", + "library", + "this", + "break", + "factory", + "mixin", + "throw", + "case", + "false", + "new", + "true", + "catch", + "final", + "null", + "try", + "class", + "on", + "typedef", + "const", + "finally", + "operator", + "var", + "continue", + "for", + "part", + "void", + "covariant", + "function", + "required", + "when", + "default", + "get", + "rethrow", + "while", + "deferred", + "hide", + "return", + "with", + "do", + "if", + "sealed", + "yield", + "dynamic", + "implements", + "set", +]; + +export const FALLBACK_PROJECT_NAME = "hello_firebase"; diff --git a/src/frameworks/flutter/index.ts b/src/frameworks/flutter/index.ts index fa738f46131..2e21849bc38 100644 --- a/src/frameworks/flutter/index.ts +++ b/src/frameworks/flutter/index.ts @@ -7,8 +7,9 @@ import { readFile } from "fs/promises"; import { BuildResult, Discovery, FrameworkType, SupportLevel } from "../interfaces"; import { FirebaseError } from "../../error"; import { assertFlutterCliExists } from "./utils"; +import { DART_RESERVED_WORDS, FALLBACK_PROJECT_NAME } from "./constants"; -export const name = "Flutter"; +export const name = "Flutter Web"; export const type = FrameworkType.Framework; export const support = SupportLevel.Experimental; @@ -22,10 +23,37 @@ export async function discover(dir: string): Promise { return { mayWantBackend: false, publicDirectory: join(dir, "web") }; } +export function init(setup: any, config: any) { + assertFlutterCliExists(); + // Convert the projectId into a valid pubspec name https://dart.dev/tools/pub/pubspec#name + // the projectId should be safe, save hyphens which we turn into underscores here + // if it's a reserved word just give it a fallback name + const projectName = DART_RESERVED_WORDS.includes(setup.projectId) + ? FALLBACK_PROJECT_NAME + : setup.projectId.replaceAll("-", "_"); + const result = spawnSync( + "flutter", + [ + "create", + "--template=app", + `--project-name=${projectName}`, + "--overwrite", + "--platforms=web", + setup.hosting.source, + ], + { stdio: "inherit", cwd: config.projectDir } + ); + if (result.status !== 0) + throw new FirebaseError( + "We were not able to create your flutter app, create the application yourself https://docs.flutter.dev/get-started/test-drive?tab=terminal before trying again." + ); + return Promise.resolve(); +} + export function build(cwd: string): Promise { assertFlutterCliExists(); const build = spawnSync("flutter", ["build", "web"], { cwd, stdio: "inherit" }); - if (build.status) throw new FirebaseError("Unable to build your Flutter app"); + if (build.status !== 0) throw new FirebaseError("Unable to build your Flutter app"); return Promise.resolve({ wantsBackend: false }); } diff --git a/src/frameworks/flutter/utils.ts b/src/frameworks/flutter/utils.ts index 292ddaf9742..4f4254df4bf 100644 --- a/src/frameworks/flutter/utils.ts +++ b/src/frameworks/flutter/utils.ts @@ -3,5 +3,8 @@ import { FirebaseError } from "../../error"; export function assertFlutterCliExists() { const process = spawnSync("flutter", ["--version"], { stdio: "ignore" }); - if (process.status) throw new FirebaseError("Flutter CLI not found."); + if (process.status !== 0) + throw new FirebaseError( + "Flutter CLI not found, follow the instructions here https://docs.flutter.dev/get-started/install before trying again." + ); } diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index 9948312ff94..a3a937153fa 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -421,7 +421,7 @@ export async function prepareFrameworks( cwd: functionsDist, } ); - if (result.status) throw new Error(`Error running \`npm pack\` at ${path}`); + if (result.status !== 0) throw new Error(`Error running \`npm pack\` at ${path}`); const { filename } = JSON.parse(result.stdout.toString())[0]; packageJson.dependencies[name] = `file:${filename}`; } else { diff --git a/src/frameworks/next/index.ts b/src/frameworks/next/index.ts index 27e0814a1d9..0d543cd07ed 100644 --- a/src/frameworks/next/index.ts +++ b/src/frameworks/next/index.ts @@ -515,7 +515,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: st cwd: sourceDir, timeout: BUNDLE_NEXT_CONFIG_TIMEOUT, }); - if (bundle.status) { + if (bundle.status !== 0) { throw new FirebaseError(bundle.stderr.toString()); } } catch (e: any) { diff --git a/src/test/frameworks/astro/index.spec.ts b/src/test/frameworks/astro/index.spec.ts index 27f02a83257..ef2289de609 100644 --- a/src/test/frameworks/astro/index.spec.ts +++ b/src/test/frameworks/astro/index.spec.ts @@ -1,8 +1,7 @@ import { expect } from "chai"; import * as sinon from "sinon"; import { EventEmitter } from "events"; -import type { ChildProcess } from "child_process"; -import { Readable, Writable } from "stream"; +import { Writable } from "stream"; import * as crossSpawn from "cross-spawn"; import * as fsExtra from "fs-extra"; @@ -209,10 +208,11 @@ describe("Astro", () => { }); it("should build an Astro SSR app", async () => { - const process = new EventEmitter() as ChildProcess; + const process = new EventEmitter() as any; process.stdin = new Writable(); - process.stdout = new EventEmitter() as Readable; - process.stderr = new EventEmitter() as Readable; + process.stdout = new EventEmitter(); + process.stderr = new EventEmitter(); + process.status = 0; const cwd = "."; const publicDir = Math.random().toString(36).split(".")[1]; @@ -233,7 +233,7 @@ describe("Astro", () => { const cli = Math.random().toString(36).split(".")[1]; sandbox.stub(frameworkUtils, "getNodeModuleBin").withArgs("astro", cwd).returns(cli); - sandbox.stub(crossSpawn, "spawn").withArgs(cli, ["build"], { cwd }).returns(process); + const stub = sandbox.stub(crossSpawn, "sync").returns(process); const result = build(cwd); @@ -242,14 +242,10 @@ describe("Astro", () => { expect(await result).to.deep.equal({ wantsBackend: true, }); + sinon.assert.calledWith(stub, cli, ["build"], { cwd, stdio: "inherit" }); }); it("should fail to build an Astro SSR app w/wrong adapter", async () => { - const process = new EventEmitter() as ChildProcess; - process.stdin = new Writable(); - process.stdout = new EventEmitter() as Readable; - process.stderr = new EventEmitter() as Readable; - const cwd = "."; const publicDir = Math.random().toString(36).split(".")[1]; sandbox @@ -269,7 +265,6 @@ describe("Astro", () => { const cli = Math.random().toString(36).split(".")[1]; sandbox.stub(frameworkUtils, "getNodeModuleBin").withArgs("astro", cwd).returns(cli); - sandbox.stub(crossSpawn, "spawn").withArgs(cli, ["build"], { cwd }).returns(process); await expect(build(cwd)).to.eventually.rejectedWith( FirebaseError, @@ -278,10 +273,11 @@ describe("Astro", () => { }); it("should build an Astro static app", async () => { - const process = new EventEmitter() as ChildProcess; + const process = new EventEmitter() as any; process.stdin = new Writable(); - process.stdout = new EventEmitter() as Readable; - process.stderr = new EventEmitter() as Readable; + process.stdout = new EventEmitter(); + process.stderr = new EventEmitter(); + process.status = 0; const cwd = "."; const publicDir = Math.random().toString(36).split(".")[1]; @@ -299,7 +295,7 @@ describe("Astro", () => { const cli = Math.random().toString(36).split(".")[1]; sandbox.stub(frameworkUtils, "getNodeModuleBin").withArgs("astro", cwd).returns(cli); - sandbox.stub(crossSpawn, "spawn").withArgs(cli, ["build"], { cwd }).returns(process); + const stub = sandbox.stub(crossSpawn, "sync").returns(process); const result = build(cwd); @@ -308,6 +304,7 @@ describe("Astro", () => { expect(await result).to.deep.equal({ wantsBackend: false, }); + sinon.assert.calledWith(stub, cli, ["build"], { cwd, stdio: "inherit" }); }); }); @@ -323,14 +320,15 @@ describe("Astro", () => { }); it("should resolve with dev server output", async () => { - const process = new EventEmitter() as ChildProcess; + const process = new EventEmitter() as any; process.stdin = new Writable(); - process.stdout = new EventEmitter() as Readable; - process.stderr = new EventEmitter() as Readable; + process.stdout = new EventEmitter(); + process.stderr = new EventEmitter(); + process.status = 0; const cli = Math.random().toString(36).split(".")[1]; sandbox.stub(frameworkUtils, "getNodeModuleBin").withArgs("astro", ".").returns(cli); - sandbox.stub(crossSpawn, "spawn").withArgs(cli, ["dev"], { cwd: "." }).returns(process); + const stub = sandbox.stub(crossSpawn, "spawn").returns(process); const devModeHandle = getDevModeHandle("."); @@ -345,6 +343,7 @@ describe("Astro", () => { ); await expect(devModeHandle).eventually.be.fulfilled; + sinon.assert.calledWith(stub, cli, ["dev"], { cwd: "." }); }); }); }); diff --git a/src/test/frameworks/flutter/index.spec.ts b/src/test/frameworks/flutter/index.spec.ts index cab8bd2ed62..40590fae340 100644 --- a/src/test/frameworks/flutter/index.spec.ts +++ b/src/test/frameworks/flutter/index.spec.ts @@ -1,15 +1,14 @@ import { expect } from "chai"; import * as sinon from "sinon"; import { EventEmitter } from "events"; -import type { ChildProcess } from "child_process"; -import { Readable, Writable } from "stream"; +import { Writable } from "stream"; import * as crossSpawn from "cross-spawn"; import * as fsExtra from "fs-extra"; import * as fsPromises from "fs/promises"; import { join } from "path"; import * as flutterUtils from "../../../frameworks/flutter/utils"; -import { discover, build, ɵcodegenPublicDirectory } from "../../../frameworks/flutter"; +import { discover, build, ɵcodegenPublicDirectory, init } from "../../../frameworks/flutter"; describe("Flutter", () => { describe("discovery", () => { @@ -93,25 +92,70 @@ describe("Flutter", () => { }); it("should build", async () => { - const process = new EventEmitter() as ChildProcess; + const process = new EventEmitter() as any; process.stdin = new Writable(); - process.stdout = new EventEmitter() as Readable; - process.stderr = new EventEmitter() as Readable; + process.stdout = new EventEmitter(); + process.stderr = new EventEmitter(); + process.status = 0; sandbox.stub(flutterUtils, "assertFlutterCliExists").returns(undefined); const cwd = "."; - sandbox - .stub(crossSpawn, "sync") - .withArgs("flutter", ["build", "web"], { cwd, stdio: "inherit" }) - .returns(process as any); + const stub = sandbox.stub(crossSpawn, "sync").returns(process as any); const result = build(cwd); expect(await result).to.deep.equal({ wantsBackend: false, }); + sinon.assert.calledWith(stub, "flutter", ["build", "web"], { cwd, stdio: "inherit" }); + }); + }); + + describe("init", () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it("should create a new project", async () => { + const process = new EventEmitter() as any; + process.stdin = new Writable(); + process.stdout = new EventEmitter(); + process.stderr = new EventEmitter(); + process.status = 0; + + sandbox.stub(flutterUtils, "assertFlutterCliExists").returns(undefined); + + const projectId = "asdflj-ao9iu4__49"; + const projectName = "asdflj_ao9iu4__49"; + const projectDir = "asfijreou5o"; + const source = "asflijrelijf"; + + const stub = sandbox.stub(crossSpawn, "sync").returns(process as any); + + const result = init({ projectId, hosting: { source } }, { projectDir }); + + expect(await result).to.eql(undefined); + sinon.assert.calledWith( + stub, + "flutter", + [ + "create", + "--template=app", + `--project-name=${projectName}`, + "--overwrite", + "--platforms=web", + source, + ], + { cwd: projectDir, stdio: "inherit" } + ); }); }); }); diff --git a/src/test/frameworks/flutter/utils.spec.ts b/src/test/frameworks/flutter/utils.spec.ts index aa770d73bf7..c5a9466e586 100644 --- a/src/test/frameworks/flutter/utils.spec.ts +++ b/src/test/frameworks/flutter/utils.spec.ts @@ -1,8 +1,7 @@ import { expect } from "chai"; import * as sinon from "sinon"; import { EventEmitter } from "events"; -import type { ChildProcess } from "child_process"; -import { Readable, Writable } from "stream"; +import { Writable } from "stream"; import * as crossSpawn from "cross-spawn"; import { assertFlutterCliExists } from "../../../frameworks/flutter/utils"; @@ -20,17 +19,16 @@ describe("Flutter utils", () => { }); it("should return void, if !status", () => { - const process = new EventEmitter() as ChildProcess; + const process = new EventEmitter() as any; process.stdin = new Writable(); - process.stdout = new EventEmitter() as Readable; - process.stderr = new EventEmitter() as Readable; + process.stdout = new EventEmitter(); + process.stderr = new EventEmitter(); + process.status = 0; - sandbox - .stub(crossSpawn, "sync") - .withArgs("flutter", ["--version"], { stdio: "ignore" }) - .returns(process as any); + const stub = sandbox.stub(crossSpawn, "sync").returns(process as any); expect(assertFlutterCliExists()).to.be.undefined; + sinon.assert.calledWith(stub, "flutter", ["--version"], { stdio: "ignore" }); }); }); }); From 339df312ea2b829d922e72b1023d652e68dee170 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Fri, 19 May 2023 18:50:26 +0000 Subject: [PATCH 012/320] 12.1.0 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 1a79a90c491..03bb6d3cdbc 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.0.1", + "version": "12.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.0.1", + "version": "12.1.0", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index 21bee0bc4ab..7b1360d12de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.0.1", + "version": "12.1.0", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From 288d85b5d911199840daf8c741960313285eb425 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Fri, 19 May 2023 18:50:42 +0000 Subject: [PATCH 013/320] [firebase-release] Removed change log and reset repo after 12.1.0 release --- CHANGELOG.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55aae1b1536..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +0,0 @@ -- Fixes an issue running `firebase emulators:start` when Python Cloud Functions directory path has spaces. (#5854) -- Add support for nodejs20 for Cloud Functions for Firebase. (#5837) -- Add Flutter Web as an option in "firebase init hosting" (#5864) -- Some failures while building Web Frameworks were not being caught (#5864) From fa39e4711d825224304e103d58e2ed4c08803808 Mon Sep 17 00:00:00 2001 From: Kevin Cheung Date: Fri, 19 May 2023 12:59:55 -0700 Subject: [PATCH 014/320] Update min version for frameworks (#5865) --- src/frameworks/docs/_includes/_before-you-begin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frameworks/docs/_includes/_before-you-begin.md b/src/frameworks/docs/_includes/_before-you-begin.md index e0815b7bb42..2811dbad248 100644 --- a/src/frameworks/docs/_includes/_before-you-begin.md +++ b/src/frameworks/docs/_includes/_before-you-begin.md @@ -3,7 +3,7 @@ Before you get started deploying your app to Firebase, review the following requirements and options: -- {{firebase_cli}} version 11.14.2 or later. Make sure to +- {{firebase_cli}} version 12.1.0 or later. Make sure to [install the {{cli}}](/docs/cli#install_the_firebase_cli) using your preferred method. - Optional: Billing enabled on your Firebase project From f21c068b9f6cd8e4a23b9cdeab2d16832f00c72f Mon Sep 17 00:00:00 2001 From: Kevin Cheung Date: Fri, 19 May 2023 13:26:40 -0700 Subject: [PATCH 015/320] Update flutter.md (#5866) --- src/frameworks/docs/flutter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frameworks/docs/flutter.md b/src/frameworks/docs/flutter.md index cde055c7ee9..c54274b060d 100644 --- a/src/frameworks/docs/flutter.md +++ b/src/frameworks/docs/flutter.md @@ -11,7 +11,7 @@ page_type: guide # Integrate Flutter Web With the Firebase framework-aware {{cli}}, you can deploy your Flutter application -to Firebase and serve dynamic content to your users. +to Firebase. <<_includes/_preview-disclaimer.md>> From 528aedda9fd27bd97c6e804020e81bfec2475547 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 22 May 2023 07:22:52 -0700 Subject: [PATCH 016/320] Improve error message when function deployment fails due to quota issues (#5867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When function deployment fails due to insufficient quota on Cloud Run, the error message is difficult to understand: ``` i functions: creating Node.js 18 function helloWorld(us-east4)... ⚠ functions: HTTP Error: 400, Could not create Cloud Run service helloworld. spec.template.spec.containers.resources.limits.cpu: Invalid value specified for cpu. For the specified value, maxScale may not exceed 10. Consider running your workload in a region with greater capacity, decreasing your requested cpu-per-instance, or requesting an increase in quota for this region if you are seeing sustained usage near this limit, see https://cloud.google.com/run/quotas. Your project may gain access to further scaling by adding billing information to your account. ``` Updated error message, which we hope is clearer and actionable: ``` i functions: creating Node.js 18 (2nd Gen) function helloWorld(us-east4)... ⚠ functions: Your current project quotas don't allow for the current max instances setting of 100. Either reduce this function's maxInstances, or request a quota increase on the underlying Cloud Run service at https://cloud.google.com/run/quotas. ⚠ functions: You can adjust the max instances value in your function's runtime options: setGlobalOptions({maxInstances: 10}) ``` --- CHANGELOG.md | 1 + src/deploy/functions/functionsDeployHelper.ts | 10 +++ src/deploy/functions/release/fabricator.ts | 7 +- src/gcp/cloudfunctionsv2.ts | 69 ++++++++++++------- 4 files changed, 60 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..d558deb3b37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Update error message when function deploy fails due to quota. (#5867) diff --git a/src/deploy/functions/functionsDeployHelper.ts b/src/deploy/functions/functionsDeployHelper.ts index 566f30367f6..79c0e388b8b 100644 --- a/src/deploy/functions/functionsDeployHelper.ts +++ b/src/deploy/functions/functionsDeployHelper.ts @@ -124,6 +124,16 @@ export function getEndpointFilters(options: { only?: string }): EndpointFilter[] return filters; } +/** + * Get human friendly name for the given function platform + */ +export function getHumanFriendlyPlatformName(platform: backend.Endpoint["platform"]): string { + if (platform === "gcfv1") { + return "1st Gen"; + } + return "2nd Gen"; +} + /** * Generate label for a function. */ diff --git a/src/deploy/functions/release/fabricator.ts b/src/deploy/functions/release/fabricator.ts index d05e2bfcba7..1ca388f9f43 100644 --- a/src/deploy/functions/release/fabricator.ts +++ b/src/deploy/functions/release/fabricator.ts @@ -26,6 +26,7 @@ import * as utils from "../../../utils"; import * as services from "../services"; import { AUTH_BLOCKING_EVENTS } from "../../../functions/events/v1"; import { getDefaultComputeServiceAgent } from "../checkIam"; +import { getHumanFriendlyPlatformName } from "../functionsDeployHelper"; // TODO: Tune this for better performance. const gcfV1PollerOptions: Omit = { @@ -680,8 +681,12 @@ export class Fabricator { logOpStart(op: string, endpoint: backend.Endpoint): void { const runtime = getHumanFriendlyRuntimeName(endpoint.runtime); + const platform = getHumanFriendlyPlatformName(endpoint.platform); const label = helper.getFunctionLabel(endpoint); - utils.logLabeledBullet("functions", `${op} ${runtime} function ${clc.bold(label)}...`); + utils.logLabeledBullet( + "functions", + `${op} ${runtime} (${platform}) function ${clc.bold(label)}...` + ); } logOpSuccess(op: string, endpoint: backend.Endpoint): void { diff --git a/src/gcp/cloudfunctionsv2.ts b/src/gcp/cloudfunctionsv2.ts index 99bb390ba00..73cada4acc5 100644 --- a/src/gcp/cloudfunctionsv2.ts +++ b/src/gcp/cloudfunctionsv2.ts @@ -1,5 +1,3 @@ -import * as clc from "colorette"; - import { Client, ClientVerbOptions } from "../apiv2"; import { FirebaseError } from "../error"; import { functionsV2Origin } from "../api"; @@ -22,6 +20,9 @@ import { RequireKeys } from "../metaprogramming"; export const API_VERSION = "v2"; +// Defined by Cloud Run: https://cloud.google.com/run/docs/configuring/max-instances#setting +const DEFAULT_MAX_INSTANCE_COUNT = 100; + const client = new Client({ urlPrefix: functionsV2Origin, auth: true, @@ -234,37 +235,53 @@ export function mebibytes(memory: string): number { /** * Logs an error from a failed function deployment. - * @param funcName Name of the function that was unsuccessfully deployed. + * @param func The function that was unsuccessfully deployed. * @param type Type of deployment - create, update, or delete. * @param err The error returned from the operation. */ -function functionsOpLogReject(funcName: string, type: string, err: any): void { - utils.logWarning(clc.bold(clc.yellow("functions:")) + ` ${err?.message}`); - if (err?.context?.response?.statusCode === 429) { - utils.logWarning( - `${clc.bold( - clc.yellow("functions:") - )} got "Quota Exceeded" error while trying to ${type} ${funcName}. Waiting to retry...` +function functionsOpLogReject(func: InputCloudFunction, type: string, err: any): void { + if (err?.message?.includes("maxScale may not exceed")) { + const maxInstances = func.serviceConfig.maxInstanceCount || DEFAULT_MAX_INSTANCE_COUNT; + utils.logLabeledWarning( + "functions", + `Your current project quotas don't allow for the current max instances setting of ${maxInstances}. ` + + "Either reduce this function's maxInstances, or request a quota increase on the underlying Cloud Run service " + + "at https://cloud.google.com/run/quotas." ); - } else if ( - err?.message.includes( - "If you recently started to use Eventarc, it may take a few minutes before all necessary permissions are propagated to the Service Agent" - ) - ) { - utils.logWarning( - `${clc.bold( - clc.yellow("functions:") - )} since this is your first time using functions v2, we need a little bit longer to finish setting everything up, please retry the deployment in a few minutes.` + const suggestedFix = func.buildConfig.runtime.startsWith("python") + ? "firebase_functions.options.set_global_options(max_instances=10)" + : "setGlobalOptions({maxInstances: 10})"; + utils.logLabeledWarning( + "functions", + `You can adjust the max instances value in your function's runtime options:\n\t${suggestedFix}` ); } else { - utils.logWarning( - clc.bold(clc.yellow("functions:")) + " failed to " + type + " function " + funcName + utils.logLabeledWarning("functions", `${err?.message}`); + if (err?.context?.response?.statusCode === 429) { + utils.logLabeledWarning( + "functions", + `Got "Quota Exceeded" error while trying to ${type} ${func.name}. Waiting to retry...` + ); + } else if ( + err?.message?.includes( + "If you recently started to use Eventarc, it may take a few minutes before all necessary permissions are propagated to the Service Agent" + ) + ) { + utils.logLabeledWarning( + "functions", + `Since this is your first time using functions v2, we need a little bit longer to finish setting everything up, please retry the deployment in a few minutes.` + ); + } + utils.logLabeledWarning( + "functions", + + ` failed to ${type} function ${func.name}` ); } - throw new FirebaseError(`Failed to ${type} function ${funcName}`, { + throw new FirebaseError(`Failed to ${type} function ${func.name}`, { original: err, status: err?.context?.response?.statusCode, - context: { function: funcName }, + context: { function: func.name }, }); } @@ -311,7 +328,7 @@ export async function createFunction(cloudFunction: InputCloudFunction): Promise ); return res.body; } catch (err: any) { - throw functionsOpLogReject(cloudFunction.name, "create", err); + throw functionsOpLogReject(cloudFunction, "create", err); } } @@ -414,7 +431,7 @@ export async function updateFunction(cloudFunction: InputCloudFunction): Promise ); return res.body; } catch (err: any) { - throw functionsOpLogReject(cloudFunction.name, "update", err); + throw functionsOpLogReject(cloudFunction, "update", err); } } @@ -427,7 +444,7 @@ export async function deleteFunction(cloudFunction: string): Promise const res = await client.delete(cloudFunction); return res.body; } catch (err: any) { - throw functionsOpLogReject(cloudFunction, "update", err); + throw functionsOpLogReject({ name: cloudFunction } as InputCloudFunction, "update", err); } } From 03b3ad24906027de2f7719f0f09754996a97694d Mon Sep 17 00:00:00 2001 From: Fred Zhang Date: Mon, 22 May 2023 07:53:32 -0700 Subject: [PATCH 017/320] RTDB emulator 4.11.2 (#5863) --- CHANGELOG.md | 2 ++ src/emulator/downloadableEmulators.ts | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d558deb3b37..02de4fccdba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,3 @@ - Update error message when function deploy fails due to quota. (#5867) +- Fixes RTDB emulator 127.0.0.1 namespace resolution bug. (#5863) +- Improves RTDB emulator to GCF emulator network reliability. (#5863) diff --git a/src/emulator/downloadableEmulators.ts b/src/emulator/downloadableEmulators.ts index 43bf7eefa88..072fb699a58 100644 --- a/src/emulator/downloadableEmulators.ts +++ b/src/emulator/downloadableEmulators.ts @@ -28,9 +28,9 @@ const CACHE_DIR = const EMULATOR_UPDATE_DETAILS: { [s in DownloadableEmulators]: EmulatorUpdateDetails } = { database: { - version: "4.11.0", - expectedSize: 34318940, - expectedChecksum: "311609538bd65666eb724ef47c2e6466", + version: "4.11.2", + expectedSize: 34495935, + expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63", }, firestore: { version: "1.17.4", From cfb94a2af8637fad096292fcb8a94e2a59c49843 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Mon, 22 May 2023 14:31:19 -0700 Subject: [PATCH 018/320] Improve cleanup process when reloading emulated functions in debug mode. --- src/emulator/functionsEmulator.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/emulator/functionsEmulator.ts b/src/emulator/functionsEmulator.ts index 78fd82d2711..f350d2d6d33 100644 --- a/src/emulator/functionsEmulator.ts +++ b/src/emulator/functionsEmulator.ts @@ -561,7 +561,12 @@ export class FunctionsEmulator implements EmulatorInstance { } // Before loading any triggers we need to make sure there are no 'stale' workers // in the pool that would cause us to run old code. - this.workerPools[emulatableBackend.codebase].refresh(); + if (this.debugMode) { + // Kill the workerPool. This should clean up all inspectors connected to the debug port. + this.workerPools[emulatableBackend.codebase].exit(); + } else { + this.workerPools[emulatableBackend.codebase].refresh(); + } // reset blocking functions config for reloads this.blockingFunctionsConfig = {}; From e40b297713dec0c79e05ce314ceaf264d18e2d9c Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Mon, 22 May 2023 14:32:55 -0700 Subject: [PATCH 019/320] Revert "Improve cleanup process when reloading emulated functions in debug mode." This reverts commit cfb94a2af8637fad096292fcb8a94e2a59c49843. --- src/emulator/functionsEmulator.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/emulator/functionsEmulator.ts b/src/emulator/functionsEmulator.ts index f350d2d6d33..78fd82d2711 100644 --- a/src/emulator/functionsEmulator.ts +++ b/src/emulator/functionsEmulator.ts @@ -561,12 +561,7 @@ export class FunctionsEmulator implements EmulatorInstance { } // Before loading any triggers we need to make sure there are no 'stale' workers // in the pool that would cause us to run old code. - if (this.debugMode) { - // Kill the workerPool. This should clean up all inspectors connected to the debug port. - this.workerPools[emulatableBackend.codebase].exit(); - } else { - this.workerPools[emulatableBackend.codebase].refresh(); - } + this.workerPools[emulatableBackend.codebase].refresh(); // reset blocking functions config for reloads this.blockingFunctionsConfig = {}; From bea955f9175d9c4b2204ba3ff20b8a23f9497360 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Mon, 22 May 2023 17:48:52 -0400 Subject: [PATCH 020/320] Nuxt, baseURL, and SSG fixes (#5716) * Handle Nuxt bundled dependencies * Add fast dev-mode to Nuxt 2 * Handle ssr true/false in Nuxt apps in a more conventional way * Import all the integrations, rather than dynamically require * Leave it to the framework to rewrite as an SPA * Handle Nuxt3 baseURL * SPAs for Nuxt3 and Angular now respect baseUrl * If the Nuxt version couldn't be determined, assume Nuxt v3 * Nuxt used process.cwd in a couple places, guard against this * Allow for Angular apps leveraging serveOptimizedImages to still be treated as an SPA --- CHANGELOG.md | 4 + src/firebaseConfig.ts | 2 +- src/frameworks/angular/index.ts | 23 +++- src/frameworks/angular/utils.ts | 2 + src/frameworks/express/index.ts | 8 +- src/frameworks/frameworks.ts | 29 +++++ src/frameworks/index.ts | 30 ++--- src/frameworks/interfaces.ts | 8 +- src/frameworks/nuxt/index.ts | 78 ++++++----- src/frameworks/nuxt/interfaces.ts | 4 + src/frameworks/nuxt2/index.ts | 173 +++++++++++-------------- src/frameworks/utils.ts | 3 +- src/frameworks/vite/index.ts | 2 + src/test/frameworks/nuxt/index.spec.ts | 15 +++ 14 files changed, 220 insertions(+), 161 deletions(-) create mode 100644 src/frameworks/frameworks.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 02de4fccdba..c83cf3e9bd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ - Update error message when function deploy fails due to quota. (#5867) - Fixes RTDB emulator 127.0.0.1 namespace resolution bug. (#5863) - Improves RTDB emulator to GCF emulator network reliability. (#5863) +- Allow for Angular developers to both target a PWA and leverage `serveOptimizedImages`. (#5716) +- Multi-page applications that are fully staticly rendered are no longer treated as PWAs. (#5716) +- Add fast dev-mode support for devlopers using Nuxt v2. (#5716) +- Respect `ssr: false` and `baseURL` when using Nuxt. (#5716) diff --git a/src/firebaseConfig.ts b/src/firebaseConfig.ts index f016f4031bb..f1395ba13c7 100644 --- a/src/firebaseConfig.ts +++ b/src/firebaseConfig.ts @@ -52,7 +52,7 @@ type FirestoreMultiple = ({ export type HostingSource = { glob: string } | { source: string } | { regex: string }; -type HostingRedirects = HostingSource & { +export type HostingRedirects = HostingSource & { destination: string; type?: number; }; diff --git a/src/frameworks/angular/index.ts b/src/frameworks/angular/index.ts index 1c92924fd3c..6fe91d936bc 100644 --- a/src/frameworks/angular/index.ts +++ b/src/frameworks/angular/index.ts @@ -1,4 +1,4 @@ -import { join } from "path"; +import { join, posix } from "path"; import { execSync } from "child_process"; import { spawn, sync as spawnSync } from "cross-spawn"; import { copy, pathExists } from "fs-extra"; @@ -53,7 +53,9 @@ export async function init(setup: any, config: any) { } export async function build(dir: string): Promise { - const { targets, serverTarget, serveOptimizedImages, locales } = await getBuildConfig(dir); + const { targets, serverTarget, serveOptimizedImages, locales, baseHref } = await getBuildConfig( + dir + ); await warnIfCustomBuildScript(dir, name, DEFAULT_BUILD_SCRIPT); for (const target of targets) { // TODO there is a bug here. Spawn for now. @@ -65,15 +67,24 @@ export async function build(dir: string): Promise { }); if (result.status !== 0) throw new FirebaseError(`Unable to build ${target}`); } + const wantsBackend = !!serverTarget || serveOptimizedImages; + const rewrites = serverTarget + ? [] + : [ + { + source: posix.join(baseHref, "**"), + destination: posix.join(baseHref, "index.html"), + }, + ]; const i18n = !!locales; - return { wantsBackend, i18n }; + return { wantsBackend, i18n, rewrites }; } export async function getDevModeHandle(dir: string) { const { targetStringFromTarget } = relativeRequire(dir, "@angular-devkit/architect"); const { serveTarget } = await getContext(dir); - if (!serveTarget) return; + if (!serveTarget) throw new Error("Could not find the serveTarget"); const host = new Promise((resolve) => { // Can't use scheduleTarget since that—like prerender—is failing on an ESM bug // will just grep for the hostname @@ -126,6 +137,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: st } = await getServerConfig(sourceDir); const dotEnv = { __NG_BROWSER_OUTPUT_PATH__: browserOutputPath }; + let rewriteSource: string | undefined = undefined; await Promise.all([ serverOutputPath @@ -182,7 +194,8 @@ exports.handle = function(req,res) { bootstrapScript = `exports.handle = require('./${serverOutputPath}/main.js').app();\n`; } else { bootstrapScript = `exports.handle = (res, req) => req.sendStatus(404);\n`; + rewriteSource = posix.join(baseUrl, "__image__"); } - return { bootstrapScript, packageJson, baseUrl, dotEnv }; + return { bootstrapScript, packageJson, baseUrl, dotEnv, rewriteSource }; } diff --git a/src/frameworks/angular/utils.ts b/src/frameworks/angular/utils.ts index 7581cd2b3e0..81457df3b3b 100644 --- a/src/frameworks/angular/utils.ts +++ b/src/frameworks/angular/utils.ts @@ -327,6 +327,7 @@ export async function getBuildConfig(sourceDir: string) { const { targetStringFromTarget } = relativeRequire(sourceDir, "@angular-devkit/architect"); const { browserTarget, + baseHref, prerenderTarget, serverTarget, architectHost, @@ -339,6 +340,7 @@ export async function getBuildConfig(sourceDir: string) { const locales = await localesForTarget(sourceDir, architectHost, browserTarget, workspaceProject); return { targets, + baseHref, serverTarget, locales, serveOptimizedImages, diff --git a/src/frameworks/express/index.ts b/src/frameworks/express/index.ts index fe31e5dab67..1acc1b6c8f6 100644 --- a/src/frameworks/express/index.ts +++ b/src/frameworks/express/index.ts @@ -23,9 +23,9 @@ async function getConfig(root: string) { export async function discover(dir: string) { if (!(await pathExists(join(dir, "package.json")))) return; - const { serveDir } = await getConfig(dir); - if (!serveDir) return; - return { mayWantBackend: true }; + const { serveDir: publicDirectory } = await getConfig(dir); + if (!publicDirectory) return; + return { mayWantBackend: true, publicDirectory }; } export async function build(cwd: string): Promise { @@ -95,7 +95,7 @@ async function getBootstrapScript( export async function ɵcodegenFunctionsDirectory(root: string, dest: string) { const bootstrapScript = await getBootstrapScript(root); - if (!bootstrapScript) return; + if (!bootstrapScript) throw new Error("Cloud not find bootstrapScript"); await mkdir(dest, { recursive: true }); const { packageJson } = await getConfig(root); diff --git a/src/frameworks/frameworks.ts b/src/frameworks/frameworks.ts new file mode 100644 index 00000000000..942ea9aa091 --- /dev/null +++ b/src/frameworks/frameworks.ts @@ -0,0 +1,29 @@ +import * as angular from "./angular"; +import * as astro from "./astro"; +import * as express from "./express"; +import * as lit from "./lit"; +import * as next from "./next"; +import * as nuxt from "./nuxt"; +import * as nuxt2 from "./nuxt2"; +import * as preact from "./preact"; +import * as svelte from "./svelte"; +import * as svelekit from "./sveltekit"; +import * as react from "./react"; +import * as vite from "./vite"; + +import { Framework } from "./interfaces"; + +export const WebFrameworks: Record = { + angular, + astro, + express, + lit, + next, + nuxt, + nuxt2, + preact, + svelte, + svelekit, + react, + vite, +}; diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index a3a937153fa..96e2e278ac6 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -267,6 +267,7 @@ export async function prepareFrameworks( codegenFunctionsDirectory = codegenDevModeFunctionsDirectory; } } else { + const buildResult = await memoizeBuild(getProjectPath(), build, [firebaseDefaults]); const { wantsBackend = false, rewrites = [], @@ -274,7 +275,7 @@ export async function prepareFrameworks( headers = [], trailingSlash, i18n = false, - } = (await memoizeBuild(getProjectPath(), build, [firebaseDefaults])) || {}; + }: BuildResult = buildResult || {}; config.rewrites.push(...rewrites); config.redirects.push(...redirects); @@ -361,16 +362,20 @@ export async function prepareFrameworks( frameworksEntry = framework, baseUrl = "", dotEnv = {}, + rewriteSource = posix.join(baseUrl, "**"), } = await codegenFunctionsDirectory(getProjectPath(), functionsDist); - config.rewrites.push({ - source: posix.normalize(posix.join(baseUrl, "**")), - function: { - functionId, - region: ssrRegion, - pinTag: experiments.isEnabled("pintags"), + config.rewrites = [ + { + source: rewriteSource, + function: { + functionId, + region: ssrRegion, + pinTag: experiments.isEnabled("pintags"), + }, }, - }); + ...config.rewrites, + ]; // Set the framework entry in the env variables to handle generation of the functions.yaml process.env.__FIREBASE_FRAMEWORKS_ENTRY__ = frameworksEntry; @@ -421,7 +426,8 @@ export async function prepareFrameworks( cwd: functionsDist, } ); - if (result.status !== 0) throw new Error(`Error running \`npm pack\` at ${path}`); + if (result.status !== 0) + throw new FirebaseError(`Error running \`npm pack\` at ${path}`); const { filename } = JSON.parse(result.stdout.toString())[0]; packageJson.dependencies[name] = `file:${filename}`; } else { @@ -505,12 +511,6 @@ ${ if (await pathExists(functionsDist)) { await rm(functionsDist, { recursive: true }); } - // No function, treat as an SPA - // TODO(jamesdaniels) be smarter about this, leave it to the framework? - config.rewrites.push({ - source: "**", - destination: "/index.html", - }); } if (firebaseDefaults) { diff --git a/src/frameworks/interfaces.ts b/src/frameworks/interfaces.ts index bb522423ec6..076769225dc 100644 --- a/src/frameworks/interfaces.ts +++ b/src/frameworks/interfaces.ts @@ -1,5 +1,6 @@ import { IncomingMessage, ServerResponse } from "http"; import { EmulatorInfo } from "../emulator/types"; +import { HostingHeaders, HostingRedirects, HostingRewrites } from "../firebaseConfig"; // These serve as the order of operations for discovery // E.g, a framework utilizing Vite should be given priority @@ -23,9 +24,9 @@ export interface Discovery { } export interface BuildResult { - rewrites?: any[]; - redirects?: any[]; - headers?: any[]; + rewrites?: HostingRewrites[]; + redirects?: HostingRedirects[]; + headers?: HostingHeaders[]; wantsBackend?: boolean; trailingSlash?: boolean; i18n?: boolean; @@ -60,6 +61,7 @@ export interface Framework { frameworksEntry?: string; baseUrl?: string; dotEnv?: Record; + rewriteSource?: string; }>; } diff --git a/src/frameworks/nuxt/index.ts b/src/frameworks/nuxt/index.ts index c40903efa51..fffd1164167 100644 --- a/src/frameworks/nuxt/index.ts +++ b/src/frameworks/nuxt/index.ts @@ -1,8 +1,8 @@ -import { copy, pathExists } from "fs-extra"; +import { copy, mkdirp, pathExists } from "fs-extra"; import { readFile } from "fs/promises"; -import { join } from "path"; +import { join, posix } from "path"; import { lt } from "semver"; -import { spawn } from "cross-spawn"; +import { spawn, sync as spawnSync } from "cross-spawn"; import { FrameworkType, SupportLevel } from "../interfaces"; import { simpleProxy, warnIfCustomBuildScript, getNodeModuleBin, relativeRequire } from "../utils"; import { getNuxtVersion } from "./utils"; @@ -13,6 +13,7 @@ export const type = FrameworkType.Toolchain; import { nuxtConfigFilesExist } from "./utils"; import type { NuxtOptions } from "./interfaces"; +import { FirebaseError } from "../../error"; const DEFAULT_BUILD_SCRIPT = ["nuxt build", "nuxi build"]; @@ -21,9 +22,7 @@ const DEFAULT_BUILD_SCRIPT = ["nuxt build", "nuxi build"]; * @param dir current directory * @return undefined if project is not Nuxt 2, { mayWantBackend: true, publicDirectory: string } otherwise */ -export async function discover( - dir: string -): Promise<{ mayWantBackend: true; publicDirectory: string } | undefined> { +export async function discover(dir: string) { if (!(await pathExists(join(dir, "package.json")))) return; const anyConfigFileExists = await nuxtConfigFilesExist(dir); @@ -34,49 +33,60 @@ export async function discover( const { dir: { public: publicDirectory }, + ssr: mayWantBackend, } = await getConfig(dir); - return { publicDirectory, mayWantBackend: true }; + return { publicDirectory, mayWantBackend }; } -export async function build(root: string) { - const { buildNuxt } = await relativeRequire(root, "@nuxt/kit"); - const nuxtApp = await getNuxt3App(root); - - await warnIfCustomBuildScript(root, name, DEFAULT_BUILD_SCRIPT); - - await buildNuxt(nuxtApp); - return { wantsBackend: true }; -} - -// Nuxt 3 -async function getNuxt3App(cwd: string) { - const { loadNuxt } = await relativeRequire(cwd, "@nuxt/kit"); - return await loadNuxt({ +export async function build(cwd: string) { + await warnIfCustomBuildScript(cwd, name, DEFAULT_BUILD_SCRIPT); + const cli = getNodeModuleBin("nuxt", cwd); + const { + ssr: wantsBackend, + app: { baseURL }, + } = await getConfig(cwd); + const command = wantsBackend ? ["build"] : ["generate"]; + const build = spawnSync(cli, command, { cwd, - overrides: { - nitro: { preset: "node" }, - // TODO figure out why generate true is leading to errors - // _generate: true, - }, + stdio: "inherit", + env: { ...process.env, NITRO_PRESET: "node" }, }); + if (build.status !== 0) throw new FirebaseError("Was unable to build your Nuxt application."); + const rewrites = wantsBackend + ? [] + : [ + { + source: posix.join(baseURL, "**"), + destination: posix.join(baseURL, "200.html"), + }, + ]; + return { wantsBackend, rewrites }; } export async function ɵcodegenPublicDirectory(root: string, dest: string) { + const { + app: { baseURL }, + } = await getConfig(root); const distPath = join(root, ".output", "public"); - await copy(distPath, dest); + const fullDest = join(dest, baseURL); + await mkdirp(fullDest); + await copy(distPath, fullDest); } -export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: string) { +export async function ɵcodegenFunctionsDirectory(sourceDir: string) { + const serverDir = join(sourceDir, ".output", "server"); const packageJsonBuffer = await readFile(join(sourceDir, "package.json")); const packageJson = JSON.parse(packageJsonBuffer.toString()); - const outputPackageJsonBuffer = await readFile( - join(sourceDir, ".output", "server", "package.json") - ); - const outputPackageJson = JSON.parse(outputPackageJsonBuffer.toString()); - await copy(join(sourceDir, ".output", "server"), destDir); - return { packageJson: { ...packageJson, ...outputPackageJson }, frameworksEntry: "nuxt3" }; + packageJson.dependencies ||= {}; + packageJson.dependencies["nitro-output"] = `file:${serverDir}`; + + const { + app: { baseURL: baseUrl }, + } = await getConfig(sourceDir); + + return { packageJson, frameworksEntry: "nitro", baseUrl }; } export async function getDevModeHandle(cwd: string) { diff --git a/src/frameworks/nuxt/interfaces.ts b/src/frameworks/nuxt/interfaces.ts index 5e78aef2803..b8d02cf19c0 100644 --- a/src/frameworks/nuxt/interfaces.ts +++ b/src/frameworks/nuxt/interfaces.ts @@ -2,6 +2,10 @@ // The NuxtOptions interface is huge and depends on multiple external types // and packages. For now only the fields that are being used are defined. export interface NuxtOptions { + ssr: boolean; + app: { + baseURL: string; + }; dir: { public: string; }; diff --git a/src/frameworks/nuxt2/index.ts b/src/frameworks/nuxt2/index.ts index b77a31d0583..5609efc56d1 100644 --- a/src/frameworks/nuxt2/index.ts +++ b/src/frameworks/nuxt2/index.ts @@ -1,140 +1,117 @@ import { copy, pathExists } from "fs-extra"; import { readFile } from "fs/promises"; -import { join } from "path"; -import { lt } from "semver"; -import { relativeRequire } from "../utils"; -import { FrameworkType, SupportLevel } from "../interfaces"; +import { basename, join, relative } from "path"; +import { gte } from "semver"; -import { nuxtConfigFilesExist, getNuxtVersion } from "../nuxt/utils"; +import { SupportLevel, FrameworkType } from "../interfaces"; +import { getNodeModuleBin, relativeRequire } from "../utils"; +import { getNuxtVersion } from "../nuxt/utils"; +import { simpleProxy } from "../utils"; +import { spawn } from "cross-spawn"; export const name = "Nuxt"; export const support = SupportLevel.Experimental; export const type = FrameworkType.MetaFramework; -/** - * - * @param dir current directory - * @return undefined if project is not Nuxt 2, {mayWantBackend: true } otherwise - */ -export async function discover(dir: string): Promise<{ mayWantBackend: true } | undefined> { - if (!(await pathExists(join(dir, "package.json")))) return; - - const nuxtVersion = getNuxtVersion(dir); - const anyConfigFileExists = await nuxtConfigFilesExist(dir); - - if (!anyConfigFileExists && !nuxtVersion) return; - if (nuxtVersion && lt(nuxtVersion, "3.0.0-0")) return { mayWantBackend: true }; +async function getAndLoadNuxt(options: { rootDir: string; for: string }) { + const nuxt = await relativeRequire(options.rootDir, "nuxt/dist/nuxt.js"); + const app = await nuxt.loadNuxt(options); + await app.ready(); + return { app, nuxt }; } /** - * Get the Nuxt app - * @param cwd - * @return Nuxt app object + * + * @param rootDir current directory + * @return undefined if project is not Nuxt 2, {mayWantBackend: true } otherwise */ -async function getNuxtApp(cwd: string): Promise { - return await relativeRequire(cwd, "nuxt/dist/nuxt.js"); +export async function discover(rootDir: string) { + if (!(await pathExists(join(rootDir, "package.json")))) return; + const nuxtVersion = getNuxtVersion(rootDir); + if (!nuxtVersion || (nuxtVersion && gte(nuxtVersion, "3.0.0-0"))) return; + const { app } = await getAndLoadNuxt({ rootDir, for: "build" }); + return { mayWantBackend: true, publicDirectory: app.options.dir.static }; } /** * - * @param root nuxt project root + * @param rootDir nuxt project root * @return whether backend is needed or not */ -export async function build(root: string): Promise<{ wantsBackend: boolean }> { - const nuxt = await getNuxtApp(root); - - const nuxtApp = await nuxt.loadNuxt({ - for: "build", - rootDir: root, - }); - +export async function build(rootDir: string) { + const { app, nuxt } = await getAndLoadNuxt({ rootDir, for: "build" }); const { options: { ssr, target }, - } = await nuxt.build(nuxtApp); - - if (ssr === true && target === "server") { - return { wantsBackend: true }; - } else { - // Inform the user that static target is not supported with `ssr: false`, - // and continue with building for client side as per current Nuxt 2. - if (ssr === false && target === "static") { - console.log( - "Firebase: Nuxt 2: Static target is not supported with `ssr: false`. Please use `target: 'server'` in your `nuxt.config.js` file." - ); - console.log("Firebase: Nuxt 2: Bundling only for client side.\n"); - } - - await buildAndGenerate(nuxt, root); - return { wantsBackend: false }; - } -} -/** - * Build and generate the Nuxt app - * - * @param nuxt nuxt object - * @param root root directory - * @return void - */ -async function buildAndGenerate(nuxt: any, root: string): Promise { - const nuxtApp = await nuxt.loadNuxt({ - for: "start", - rootDir: root, - }); + } = app; + + // Nuxt seems to use process.cwd() somewhere + const cwd = process.cwd(); + process.chdir(rootDir); - const builder = await nuxt.getBuilder(nuxtApp); - const generator = new nuxt.Generator(nuxtApp, builder); + await nuxt.build(app); + const { app: generateApp } = await getAndLoadNuxt({ rootDir, for: "start" }); + const builder = await nuxt.getBuilder(generateApp); + const generator = new nuxt.Generator(generateApp, builder); await generator.generate({ build: false, init: true }); + + process.chdir(cwd); + + const wantsBackend = ssr && target === "server"; + const rewrites = wantsBackend ? [] : [{ source: "**", destination: "/200.html" }]; + + return { wantsBackend, rewrites }; } /** * Copy the static files to the destination directory whether it's a static build or server build. - * @param root + * @param rootDir * @param dest */ -export async function ɵcodegenPublicDirectory(root: string, dest: string) { - const nuxt = await getNuxtApp(root); - const nuxtConfig = await nuxt.loadNuxtConfig(); - const { ssr, target } = nuxtConfig; - - // If `target` is set to `static`, copy the generated files - // to the destination directory (i.e. `/hosting`). - if (!(ssr === true && target === "server")) { - const source = - nuxtConfig?.generate?.dir !== undefined - ? join(root, nuxtConfig?.generate?.dir) - : join(root, "dist"); - - await copy(source, dest); - } - - // Copy static assets if they exist. - const staticPath = join(root, "static"); - if (await pathExists(staticPath)) { - await copy(staticPath, dest); - } +export async function ɵcodegenPublicDirectory(rootDir: string, dest: string) { + const { + app: { options }, + } = await getAndLoadNuxt({ rootDir, for: "build" }); + await copy(options.generate.dir, dest); } -export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: string) { - const packageJsonBuffer = await readFile(join(sourceDir, "package.json")); +export async function ɵcodegenFunctionsDirectory(rootDir: string, destDir: string) { + const packageJsonBuffer = await readFile(join(rootDir, "package.json")); const packageJson = JSON.parse(packageJsonBuffer.toString()); // Get the nuxt config into an object so we can check the `target` and `ssr` properties. - const nuxt = await getNuxtApp(sourceDir); - const nuxtConfig = await nuxt.loadNuxtConfig(); + const { + app: { options }, + } = await getAndLoadNuxt({ rootDir, for: "build" }); + const { buildDir, _nuxtConfigFile: configFilePath } = options; // When starting the Nuxt 2 server, we need to copy the `.nuxt` to the destination directory (`functions`) // with the same folder name (.firebase//functions/.nuxt). // This is because `loadNuxt` (called from `firebase-frameworks`) will only look // for the `.nuxt` directory in the destination directory. - await copy(join(sourceDir, ".nuxt"), join(destDir, ".nuxt")); + await copy(buildDir, join(destDir, relative(rootDir, buildDir))); - // When using `SSR: false`, we need to copy the `nuxt.config.js` to the destination directory (`functions`) - // This is because `loadNuxt` (called from `firebase-frameworks`) will look - // for the `nuxt.config.js` file in the destination directory. - if (!nuxtConfig.ssr) { - const nuxtConfigFile = nuxtConfig._nuxtConfigFile.split("/").pop(); - await copy(nuxtConfig._nuxtConfigFile, join(destDir, nuxtConfigFile)); - } + // TODO pack this + await copy(configFilePath, join(destDir, basename(configFilePath))); return { packageJson: { ...packageJson }, frameworksEntry: "nuxt" }; } + +export async function getDevModeHandle(cwd: string) { + const host = new Promise((resolve) => { + const cli = getNodeModuleBin("nuxt", cwd); + const serve = spawn(cli, ["dev"], { cwd }); + + serve.stdout.on("data", (data: any) => { + process.stdout.write(data); + const match = data.toString().match(/(http:\/\/.+:\d+)/); + + if (match) resolve(match[1]); + }); + + serve.stderr.on("data", (data: any) => { + process.stderr.write(data); + }); + }); + + return simpleProxy(await host); +} diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index 7f36088daaa..7b5bd607aca 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -69,7 +69,8 @@ export function simpleProxy(hostOrRequestHandler: string | RequestHandler) { return async (originalReq: IncomingMessage, originalRes: ServerResponse, next: () => void) => { const { method, headers, url: path } = originalReq; if (!method || !path) { - return originalRes.end(); + originalRes.end(); + return; } // If the path is a the auth token sync URL pass through to Cloud Functions const firebaseDefaultsJSON = process.env.__FIREBASE_DEFAULTS__; diff --git a/src/frameworks/vite/index.ts b/src/frameworks/vite/index.ts index 54d1e619904..959145a867e 100644 --- a/src/frameworks/vite/index.ts +++ b/src/frameworks/vite/index.ts @@ -73,6 +73,8 @@ export async function build(root: string) { process.chdir(root); await build({ root, mode: "production" }); process.chdir(cwd); + + return { rewrites: [{ source: "**", destination: "/index.html" }] }; } export async function ɵcodegenPublicDirectory(root: string, dest: string) { diff --git a/src/test/frameworks/nuxt/index.spec.ts b/src/test/frameworks/nuxt/index.spec.ts index f3c175bee19..d2a5e9f70b7 100644 --- a/src/test/frameworks/nuxt/index.spec.ts +++ b/src/test/frameworks/nuxt/index.spec.ts @@ -31,9 +31,20 @@ describe("Nuxt 2 utils", () => { resolved: "https://registry.npmjs.org/nuxt/-/nuxt-2.15.8.tgz", overridden: false, }); + sandbox + .stub(frameworksUtils, "relativeRequire") + .withArgs(discoverNuxtDir, "nuxt/dist/nuxt.js" as any) + .resolves({ + loadNuxt: () => + Promise.resolve({ + ready: () => Promise.resolve(), + options: { dir: { static: "static" } }, + }), + }); expect(await discoverNuxt2(discoverNuxtDir)).to.deep.equal({ mayWantBackend: true, + publicDirectory: "static", }); }); @@ -50,6 +61,10 @@ describe("Nuxt 2 utils", () => { .resolves({ loadNuxtConfig: async function (): Promise { return Promise.resolve({ + ssr: true, + app: { + baseURL: "/", + }, dir: { public: "public", }, From 5c7fa9f31631bc36ff9217d9647cdfecf9b6208f Mon Sep 17 00:00:00 2001 From: Chalo Salvador Date: Tue, 23 May 2023 06:39:28 +0200 Subject: [PATCH 021/320] FIREBASE_FRAMEWORKS_BUILD_TARGET (#5572) Co-authored-by: James Daniels --- CHANGELOG.md | 1 + src/frameworks/angular/index.ts | 64 +++++++-- src/frameworks/angular/utils.ts | 222 ++++++++++++++++++++------------ src/frameworks/constants.ts | 8 ++ src/frameworks/index.ts | 45 +++++-- src/frameworks/interfaces.ts | 11 +- src/frameworks/next/index.ts | 3 +- src/frameworks/utils.ts | 34 +++++ 8 files changed, 279 insertions(+), 109 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c83cf3e9bd4..33d60ee9611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,4 @@ - Multi-page applications that are fully staticly rendered are no longer treated as PWAs. (#5716) - Add fast dev-mode support for devlopers using Nuxt v2. (#5716) - Respect `ssr: false` and `baseURL` when using Nuxt. (#5716) +- Respect `FIREBASE_FRAMEWORKS_BUILD_TARGET` environment variable to override the default build target (#5572). diff --git a/src/frameworks/angular/index.ts b/src/frameworks/angular/index.ts index 6fe91d936bc..26faa0afd72 100644 --- a/src/frameworks/angular/index.ts +++ b/src/frameworks/angular/index.ts @@ -4,7 +4,13 @@ import { spawn, sync as spawnSync } from "cross-spawn"; import { copy, pathExists } from "fs-extra"; import { mkdir } from "fs/promises"; -import { BuildResult, Discovery, FrameworkType, SupportLevel } from "../interfaces"; +import { + BuildResult, + Discovery, + FrameworkType, + SupportLevel, + BUILD_TARGET_PURPOSE, +} from "../interfaces"; import { promptOnce } from "../../prompt"; import { simpleProxy, @@ -13,7 +19,13 @@ import { warnIfCustomBuildScript, findDependency, } from "../utils"; -import { getBrowserConfig, getBuildConfig, getContext, getServerConfig } from "./utils"; +import { + getAllTargets, + getBrowserConfig, + getBuildConfig, + getContext, + getServerConfig, +} from "./utils"; import { I18N_ROOT, SHARP_VERSION } from "../constants"; import { FirebaseError } from "../../error"; @@ -52,9 +64,10 @@ export async function init(setup: any, config: any) { } } -export async function build(dir: string): Promise { +export async function build(dir: string, configuration: string): Promise { const { targets, serverTarget, serveOptimizedImages, locales, baseHref } = await getBuildConfig( - dir + dir, + configuration ); await warnIfCustomBuildScript(dir, name, DEFAULT_BUILD_SCRIPT); for (const target of targets) { @@ -81,9 +94,9 @@ export async function build(dir: string): Promise { return { wantsBackend, i18n, rewrites }; } -export async function getDevModeHandle(dir: string) { +export async function getDevModeHandle(dir: string, configuration: string) { const { targetStringFromTarget } = relativeRequire(dir, "@angular-devkit/architect"); - const { serveTarget } = await getContext(dir); + const { serveTarget } = await getContext(dir, configuration); if (!serveTarget) throw new Error("Could not find the serveTarget"); const host = new Promise((resolve) => { // Can't use scheduleTarget since that—like prerender—is failing on an ESM bug @@ -104,8 +117,15 @@ export async function getDevModeHandle(dir: string) { return simpleProxy(await host); } -export async function ɵcodegenPublicDirectory(sourceDir: string, destDir: string) { - const { outputPath, baseHref, defaultLocale, locales } = await getBrowserConfig(sourceDir); +export async function ɵcodegenPublicDirectory( + sourceDir: string, + destDir: string, + configuration: string +) { + const { outputPath, baseHref, defaultLocale, locales } = await getBrowserConfig( + sourceDir, + configuration + ); await mkdir(join(destDir, baseHref), { recursive: true }); if (locales) { await Promise.all([ @@ -122,7 +142,31 @@ export async function ɵcodegenPublicDirectory(sourceDir: string, destDir: strin } } -export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: string) { +export async function getValidBuildTargets(purpose: BUILD_TARGET_PURPOSE, dir: string) { + const validTargetNames = new Set(["development", "production"]); + try { + const { workspaceProject, browserTarget, serverTarget, serveTarget } = await getContext(dir); + const { target } = ((purpose === "serve" && serveTarget) || serverTarget || browserTarget)!; + const workspaceTarget = workspaceProject.targets.get(target)!; + Object.keys(workspaceTarget.configurations || {}).forEach((it) => validTargetNames.add(it)); + } catch (e) { + // continue + } + const allTargets = await getAllTargets(purpose, dir); + return [...validTargetNames, ...allTargets]; +} + +export async function shouldUseDevModeHandle(targetOrConfiguration: string, dir: string) { + const { serveTarget } = await getContext(dir, targetOrConfiguration); + if (!serveTarget) return false; + return serveTarget.configuration !== "production"; +} + +export async function ɵcodegenFunctionsDirectory( + sourceDir: string, + destDir: string, + configuration: string +) { const { packageJson, serverOutputPath, @@ -134,7 +178,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: st externalDependencies, baseHref: baseUrl, serveOptimizedImages, - } = await getServerConfig(sourceDir); + } = await getServerConfig(sourceDir, configuration); const dotEnv = { __NG_BROWSER_OUTPUT_PATH__: browserOutputPath }; let rewriteSource: string | undefined = undefined; diff --git a/src/frameworks/angular/utils.ts b/src/frameworks/angular/utils.ts index 81457df3b3b..47c7b5affb3 100644 --- a/src/frameworks/angular/utils.ts +++ b/src/frameworks/angular/utils.ts @@ -6,6 +6,7 @@ import { AngularI18nConfig } from "./interfaces"; import { relativeRequire, validateLocales } from "../utils"; import { FirebaseError } from "../../error"; import { join } from "path"; +import { BUILD_TARGET_PURPOSE } from "../interfaces"; async function localesForTarget( dir: string, @@ -59,8 +60,55 @@ async function localesForTarget( return { locales, defaultLocale }; } +const enum ExpectedBuilder { + ANGULAR_FIRE_DEPLOY_TARGET = "@angular/fire:deploy", + BUILD_TARGET = "@angular-devkit/build-angular:browser", + PRERENDER_TARGET = "@nguniversal/builders:prerender", + DEV_SERVER_TARGET = "@angular-devkit/build-angular:dev-server", + SSR_DEV_SERVER_TARGET = "@nguniversal/builders:ssr-dev-server", +} + +const DEV_SERVER_TARGETS: string[] = [ + ExpectedBuilder.DEV_SERVER_TARGET, + ExpectedBuilder.SSR_DEV_SERVER_TARGET, +]; + +function getValidBuilders(purpose: BUILD_TARGET_PURPOSE): string[] { + return [ + ExpectedBuilder.ANGULAR_FIRE_DEPLOY_TARGET, + ExpectedBuilder.BUILD_TARGET, + ExpectedBuilder.PRERENDER_TARGET, + ...(purpose === "deploy" ? [] : DEV_SERVER_TARGETS), + ]; +} + +export async function getAllTargets(purpose: BUILD_TARGET_PURPOSE, dir: string) { + const validBuilders = getValidBuilders(purpose); + const { NodeJsAsyncHost } = relativeRequire(dir, "@angular-devkit/core/node"); + const { workspaces } = relativeRequire(dir, "@angular-devkit/core"); + const { targetStringFromTarget } = relativeRequire(dir, "@angular-devkit/architect"); + + const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost()); + const { workspace } = await workspaces.readWorkspace(dir, host); + + const targets: string[] = []; + workspace.projects.forEach((projectDefinition, project) => { + if (projectDefinition.extensions.projectType !== "application") return; + projectDefinition.targets.forEach((targetDefinition, target) => { + if (!validBuilders.includes(targetDefinition.builder)) return; + const configurations = Object.keys(targetDefinition.configurations || {}); + if (!configurations.includes("production")) configurations.push("production"); + if (!configurations.includes("development")) configurations.push("development"); + configurations.forEach((configuration) => { + targets.push(targetStringFromTarget({ project, target, configuration })); + }); + }); + }); + return targets; +} + // TODO(jamesdaniels) memoize, dry up -export async function getContext(dir: string) { +export async function getContext(dir: string, targetOrConfiguration?: string) { const { NodeJsAsyncHost } = relativeRequire(dir, "@angular-devkit/core/node"); const { workspaces } = relativeRequire(dir, "@angular-devkit/core"); const { WorkspaceNodeModulesArchitectHost } = relativeRequire( @@ -78,13 +126,27 @@ export async function getContext(dir: string) { const architectHost = new WorkspaceNodeModulesArchitectHost(workspace, dir); const architect = new Architect(architectHost); - let project: string | undefined = (globalThis as any).NG_DEPLOY_PROJECT; + let overrideTarget: Target | undefined; + let project: string | undefined; let browserTarget: Target | undefined; let serverTarget: Target | undefined; let prerenderTarget: Target | undefined; let serveTarget: Target | undefined; let serveOptimizedImages = false; + let deployTargetName; + let configuration: string | undefined = undefined; + if (targetOrConfiguration) { + try { + overrideTarget = targetFromTargetString(targetOrConfiguration); + configuration = overrideTarget.configuration; + project = overrideTarget.project; + } catch (e) { + deployTargetName = "deploy"; + configuration = targetOrConfiguration; + } + } + if (!project) { const angularJson = parse(await host.readFile(join(dir, "angular.json"))); project = angularJson.defaultProject; @@ -100,15 +162,27 @@ export async function getContext(dir: string) { if (!project) throw new FirebaseError( - "Unable to determine the application to deploy, you should use `ng deploy` via @angular/fire." + "Unable to determine the application to deploy, specify a target via the FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable" ); const workspaceProject = workspace.projects.get(project); if (!workspaceProject) throw new FirebaseError(`No project ${project} found.`); - const deployTargetDefinition = workspaceProject.targets.get("deploy"); + if (overrideTarget) { + const target = workspaceProject.targets.get(overrideTarget.target)!; + const builder = target.builder; + if (builder === ExpectedBuilder.ANGULAR_FIRE_DEPLOY_TARGET) + deployTargetName = overrideTarget.target; + if (builder === ExpectedBuilder.BUILD_TARGET) browserTarget = overrideTarget; + if (builder === ExpectedBuilder.PRERENDER_TARGET) prerenderTarget = overrideTarget; + if (typeof builder === "string" && DEV_SERVER_TARGETS.includes(builder)) + serveTarget = overrideTarget; + } - if (deployTargetDefinition?.builder === "@angular/fire:deploy") { + const deployTargetDefinition = deployTargetName + ? workspaceProject.targets.get(deployTargetName) + : undefined; + if (deployTargetDefinition?.builder === ExpectedBuilder.ANGULAR_FIRE_DEPLOY_TARGET) { const options = deployTargetDefinition.options; if (typeof options?.prerenderTarget === "string") prerenderTarget = targetFromTargetString(options.prerenderTarget); @@ -136,83 +210,62 @@ export async function getContext(dir: string) { "Treating the application as fully rendered. Add a serverTarget to your deploy target in angular.json to utilize server-side rendering." ); } - } else if (workspaceProject.targets.has("prerender")) { - const target = workspaceProject.targets.get("prerender")!; - const configurations = Object.keys(target.configurations!); - const configuration = configurations.includes("production") - ? "production" - : target.defaultConfiguration; - if (!configuration) - throw new Error("No production or default configuration found for prerender."); - if (configuration !== "production") - console.warn( - `Using ${configuration} configuration for the prerender, we suggest adding a production target.` + } + + if (!overrideTarget && !prerenderTarget && workspaceProject.targets.has("prerender")) { + const { defaultConfiguration = "production" } = workspaceProject.targets.get("prerender")!; + prerenderTarget = { project, target: "prerender", configuration: defaultConfiguration }; + } + + if (serveTarget) { + const options = await architectHost.getOptionsForTarget(serveTarget); + if (typeof options?.browserTarget !== "string") + throw new Error( + `${serveTarget.target} browserTarget expected to be string, check your angular.json.` ); - prerenderTarget = { project, target: "prerender", configuration }; - const production = await architectHost.getOptionsForTarget(prerenderTarget); - if (typeof production?.browserTarget !== "string") - throw new Error("Prerender browserTarget expected to be string, check your angular.json."); - browserTarget = targetFromTargetString(production.browserTarget); - if (typeof production?.serverTarget !== "string") - throw new Error("Prerender serverTarget expected to be string, check your angular.json."); - serverTarget = targetFromTargetString(production.serverTarget); - } else { - if (workspaceProject.targets.has("build")) { - const target = workspaceProject.targets.get("build")!; - const configurations = Object.keys(target.configurations!); - const configuration = configurations.includes("production") - ? "production" - : target.defaultConfiguration; - if (!configuration) - throw new Error("No production or default configuration found for build."); - if (configuration !== "production") - console.warn( - `Using ${configuration} configuration for the browser deploy, we suggest adding a production target.` + browserTarget = targetFromTargetString(options.browserTarget); + if (options?.serverTarget) { + if (typeof options.serverTarget !== "string") + throw new Error( + `${serveTarget.target} serverTarget expected to be string, check your angular.json.` ); - browserTarget = { project, target: "build", configuration }; + serverTarget = targetFromTargetString(options.serverTarget); } - if (workspaceProject.targets.has("server")) { - const target = workspaceProject.targets.get("server")!; - const configurations = Object.keys(target.configurations!); - const configuration = configurations.includes("production") - ? "production" - : target.defaultConfiguration; - if (!configuration) - throw new Error("No production or default configutation found for server."); - if (configuration !== "production") - console.warn( - `Using ${configuration} configuration for the server deploy, we suggest adding a production target.` - ); - serverTarget = { project, target: "server", configuration }; + } else if (prerenderTarget) { + const options = await architectHost.getOptionsForTarget(prerenderTarget); + if (typeof options?.browserTarget !== "string") + throw new Error("Prerender browserTarget expected to be string, check your angular.json."); + browserTarget = targetFromTargetString(options.browserTarget); + if (typeof options?.serverTarget !== "string") + throw new Error("Prerender serverTarget expected to be string, check your angular.json."); + serverTarget = targetFromTargetString(options.serverTarget); + } + + if (!browserTarget && workspaceProject.targets.has("build")) { + const { defaultConfiguration = "production" } = workspaceProject.targets.get("build")!; + browserTarget = { project, target: "build", configuration: defaultConfiguration }; + } + + if (!serverTarget && workspaceProject.targets.has("server")) { + const { defaultConfiguration = "production" } = workspaceProject.targets.get("server")!; + serverTarget = { project, target: "server", configuration: defaultConfiguration }; + } + + if (!serveTarget) { + if (serverTarget && workspaceProject.targets.has("serve-ssr")) { + const { defaultConfiguration = "development" } = workspaceProject.targets.get("serve-ssr")!; + serveTarget = { project, target: "serve-ssr", configuration: defaultConfiguration }; + } else if (workspaceProject.targets.has("serve")) { + const { defaultConfiguration = "development" } = workspaceProject.targets.get("serve")!; + serveTarget = { project, target: "serve", configuration: defaultConfiguration }; } } - if (serverTarget && workspaceProject.targets.has("serve-ssr")) { - const target = workspaceProject.targets.get("serve-ssr")!; - const configurations = Object.keys(target.configurations!); - const configuration = configurations.includes("development") - ? "development" - : target.defaultConfiguration; - if (!configuration) - throw new Error("No development or default configutation found for serve-ssr."); - if (configuration !== "development") - console.warn( - `Using ${configuration} configuration for the local server, we suggest adding a development target.` - ); - serveTarget = { project, target: "serve-ssr", configuration }; - } else if (workspaceProject.targets.has("serve")) { - if (serverTarget) console.warn(`No server-ssr target found.`); - const target = workspaceProject.targets.get("serve")!; - const configurations = Object.keys(target.configurations!); - const configuration = configurations.includes("development") - ? "development" - : target.defaultConfiguration; - if (!configuration) throw new Error("No development or default configutation found for serve."); - if (configuration !== "development") - console.warn( - `Using ${configuration} configuration for the local server, we suggest adding a development target.` - ); - serveTarget = { project, target: "serve", configuration }; + if (configuration) { + if (prerenderTarget) prerenderTarget.configuration = configuration; + if (serverTarget) serverTarget.configuration = configuration; + if (browserTarget) browserTarget.configuration = configuration; + if (serveTarget) serveTarget.configuration = configuration; } if (!browserTarget) throw new FirebaseError(`No browser target on ${project}`); @@ -221,7 +274,7 @@ export async function getContext(dir: string) { throw new FirebaseError(`Couldn't find options for ${targetStringFromTarget(browserTarget)}.`); } - const baseHref = browserTargetOptions.baseHref || ""; + const baseHref = browserTargetOptions.baseHref || "/"; if (typeof baseHref !== "string") { throw new FirebaseError( `baseHref on ${targetStringFromTarget(browserTarget)} was not a string` @@ -242,8 +295,11 @@ export async function getContext(dir: string) { }; } -export async function getBrowserConfig(sourceDir: string) { - const { architectHost, browserTarget, baseHref, workspaceProject } = await getContext(sourceDir); +export async function getBrowserConfig(sourceDir: string, configuration: string) { + const { architectHost, browserTarget, baseHref, workspaceProject } = await getContext( + sourceDir, + configuration + ); const { locales, defaultLocale } = await localesForTarget( sourceDir, architectHost, @@ -257,7 +313,7 @@ export async function getBrowserConfig(sourceDir: string) { return { locales, baseHref, outputPath, defaultLocale }; } -export async function getServerConfig(sourceDir: string) { +export async function getServerConfig(sourceDir: string, configuration: string) { const { architectHost, host, @@ -266,7 +322,7 @@ export async function getServerConfig(sourceDir: string) { baseHref, workspaceProject, serveOptimizedImages, - } = await getContext(sourceDir); + } = await getContext(sourceDir, configuration); const browserTargetOptions = await architectHost.getOptionsForTarget(browserTarget); if (typeof browserTargetOptions?.outputPath !== "string") throw new Error("browserTarget output path is not a string"); @@ -323,7 +379,7 @@ export async function getServerConfig(sourceDir: string) { }; } -export async function getBuildConfig(sourceDir: string) { +export async function getBuildConfig(sourceDir: string, configuration: string) { const { targetStringFromTarget } = relativeRequire(sourceDir, "@angular-devkit/architect"); const { browserTarget, @@ -333,7 +389,7 @@ export async function getBuildConfig(sourceDir: string) { architectHost, workspaceProject, serveOptimizedImages, - } = await getContext(sourceDir); + } = await getContext(sourceDir, configuration); const targets = ( prerenderTarget ? [prerenderTarget] : [browserTarget, serverTarget].filter((it) => !!it) ).map((it) => targetStringFromTarget(it!)); diff --git a/src/frameworks/constants.ts b/src/frameworks/constants.ts index 609fad33089..592e5b9f870 100644 --- a/src/frameworks/constants.ts +++ b/src/frameworks/constants.ts @@ -68,3 +68,11 @@ export const WebFrameworks: Record = Object.fromEntries( obj && obj.name && obj.discover && obj.build && obj.type !== undefined && obj.support ) ); + +export function GET_DEFAULT_BUILD_TARGETS() { + return Promise.resolve(["production", "development"]); +} + +export function DEFAULT_SHOULD_USE_DEV_MODE_HANDLE(target: string) { + return Promise.resolve(target === "development"); +} diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index 96e2e278ac6..bd7ae7fe513 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -22,20 +22,27 @@ import { FirebaseError } from "../error"; import { requireHostingSite } from "../requireHostingSite"; import * as experiments from "../experiments"; import { implicitInit } from "../hosting/implicitInit"; -import { findDependency, conjoinOptions, frameworksCallToAction } from "./utils"; +import { + findDependency, + conjoinOptions, + frameworksCallToAction, + getFrameworksBuildTarget, +} from "./utils"; import { ALLOWED_SSR_REGIONS, DEFAULT_REGION, + DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, FIREBASE_ADMIN_VERSION, FIREBASE_FRAMEWORKS_VERSION, FIREBASE_FUNCTIONS_VERSION, + GET_DEFAULT_BUILD_TARGETS, I18N_ROOT, NODE_VERSION, SupportLevelWarnings, VALID_ENGINES, WebFrameworks, } from "./constants"; -import { BuildResult, FirebaseDefaults, Framework } from "./interfaces"; +import { BUILD_TARGET_PURPOSE, BuildResult, FirebaseDefaults, Framework } from "./interfaces"; import { logWarning } from "../utils"; import { ensureTargeted } from "../functions/ensureTargeted"; import { isDeepStrictEqual } from "util"; @@ -74,8 +81,9 @@ const BUILD_MEMO = new Map>(); // Memoize the build based on both the dir and the environment variables function memoizeBuild( dir: string, - build: (dir: string) => Promise, - deps: any[] + build: (dir: string, target: string) => Promise, + deps: any[], + target: string ) { const key = [dir, ...deps]; for (const existingKey of BUILD_MEMO.keys()) { @@ -83,7 +91,7 @@ function memoizeBuild( return BUILD_MEMO.get(existingKey); } } - const value = build(dir); + const value = build(dir, target); BUILD_MEMO.set(key, value); return value; } @@ -244,20 +252,26 @@ export async function prepareFrameworks( name, support, docsUrl, + getValidBuildTargets = GET_DEFAULT_BUILD_TARGETS, + shouldUseDevModeHandle = DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = WebFrameworks[framework]; console.log( `\n${frameworksCallToAction(SupportLevelWarnings[support](name), docsUrl, " ")}\n` ); - // TODO allow for override - const isDevMode = context._name === "serve" || context._name === "emulators:start"; const hostingEmulatorInfo = emulators.find((e) => e.name === Emulators.HOSTING); + const buildTargetPurpose: BUILD_TARGET_PURPOSE = + context._name === "deploy" ? "deploy" : context._name === "emulators:exec" ? "test" : "serve"; + const validBuildTargets = await getValidBuildTargets(buildTargetPurpose, getProjectPath()); + const frameworksBuildTarget = getFrameworksBuildTarget(buildTargetPurpose, validBuildTargets); + const useDevModeHandle = await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath()); + + let codegenFunctionsDirectory: Framework["ɵcodegenFunctionsDirectory"]; const devModeHandle = - isDevMode && + useDevModeHandle && getDevModeHandle && - (await getDevModeHandle(getProjectPath(), hostingEmulatorInfo)); - let codegenFunctionsDirectory: Framework["ɵcodegenFunctionsDirectory"]; + (await getDevModeHandle(getProjectPath(), frameworksBuildTarget, hostingEmulatorInfo)); if (devModeHandle) { config.public = relative(projectRoot, publicDirectory); // Attach the handle to options, it will be used when spinning up superstatic @@ -267,7 +281,12 @@ export async function prepareFrameworks( codegenFunctionsDirectory = codegenDevModeFunctionsDirectory; } } else { - const buildResult = await memoizeBuild(getProjectPath(), build, [firebaseDefaults]); + const buildResult = await memoizeBuild( + getProjectPath(), + build, + [firebaseDefaults, frameworksBuildTarget], + frameworksBuildTarget + ); const { wantsBackend = false, rewrites = [], @@ -286,7 +305,7 @@ export async function prepareFrameworks( if (await pathExists(hostingDist)) await rm(hostingDist, { recursive: true }); await mkdirp(hostingDist); - await ɵcodegenPublicDirectory(getProjectPath(), hostingDist, { + await ɵcodegenPublicDirectory(getProjectPath(), hostingDist, frameworksBuildTarget, { project, site, }); @@ -363,7 +382,7 @@ export async function prepareFrameworks( baseUrl = "", dotEnv = {}, rewriteSource = posix.join(baseUrl, "**"), - } = await codegenFunctionsDirectory(getProjectPath(), functionsDist); + } = await codegenFunctionsDirectory(getProjectPath(), functionsDist, frameworksBuildTarget); config.rewrites = [ { diff --git a/src/frameworks/interfaces.ts b/src/frameworks/interfaces.ts index 076769225dc..c851726b1cd 100644 --- a/src/frameworks/interfaces.ts +++ b/src/frameworks/interfaces.ts @@ -36,17 +36,19 @@ export interface Framework { discover: (dir: string) => Promise; type: FrameworkType; name: string; - build: (dir: string) => Promise; + build: (dir: string, target: string) => Promise; support: SupportLevel; docsUrl?: string; init?: (setup: any, config: any) => Promise; getDevModeHandle?: ( dir: string, + target: string, hostingEmulatorInfo?: EmulatorInfo ) => Promise<(req: IncomingMessage, res: ServerResponse, next: () => void) => void>; ɵcodegenPublicDirectory: ( dir: string, dest: string, + target: string, context: { project: string; site: string; @@ -54,7 +56,8 @@ export interface Framework { ) => Promise; ɵcodegenFunctionsDirectory?: ( dir: string, - dest: string + dest: string, + target: string ) => Promise<{ bootstrapScript?: string; packageJson: any; @@ -63,8 +66,12 @@ export interface Framework { dotEnv?: Record; rewriteSource?: string; }>; + getValidBuildTargets?: (purpose: BUILD_TARGET_PURPOSE, dir: string) => Promise; + shouldUseDevModeHandle?: (target: string, dir: string) => Promise; } +export type BUILD_TARGET_PURPOSE = "deploy" | "test" | "serve"; + // TODO pull from @firebase/util when published export interface FirebaseDefaults { config?: Object; diff --git a/src/frameworks/next/index.ts b/src/frameworks/next/index.ts index 0d543cd07ed..1a2c9360c61 100644 --- a/src/frameworks/next/index.ts +++ b/src/frameworks/next/index.ts @@ -312,6 +312,7 @@ export async function init(setup: any, config: any) { export async function ɵcodegenPublicDirectory( sourceDir: string, destDir: string, + _: string, context: { site: string; project: string } ) { const { distDir, i18n, basePath } = await getConfig(sourceDir); @@ -550,7 +551,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: st /** * Create a dev server. */ -export async function getDevModeHandle(dir: string, hostingEmulatorInfo?: EmulatorInfo) { +export async function getDevModeHandle(dir: string, _: string, hostingEmulatorInfo?: EmulatorInfo) { // throw error when using Next.js middleware with firebase serve if (!hostingEmulatorInfo) { if (await isUsingMiddleware(dir, true)) { diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index 7b5bd607aca..374297688a5 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -18,6 +18,7 @@ import { NPM_COMMAND_TIMEOUT_MILLIES, VALID_LOCALE_FORMATS, } from "./constants"; +import { BUILD_TARGET_PURPOSE } from "./interfaces"; // Use "true &&"" to keep typescript from compiling this file and rewriting // the import statement into a require @@ -277,3 +278,36 @@ export function validateLocales(locales: string[] | undefined = []) { ); } } + +export function getFrameworksBuildTarget(purpose: BUILD_TARGET_PURPOSE, validOptions: string[]) { + const frameworksBuild = process.env.FIREBASE_FRAMEWORKS_BUILD_TARGET; + if (frameworksBuild) { + if (!validOptions.includes(frameworksBuild)) { + throw new FirebaseError( + `Invalid value for FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable: ${frameworksBuild}. Valid values are: ${validOptions.join( + ", " + )}` + ); + } + return frameworksBuild; + // TODO handle other language / frameworks environment variables + } else if (process.env.NODE_ENV) { + switch (process.env.NODE_ENV) { + case "development": + return "development"; + case "production": + case "test": + return "production"; + default: + throw new FirebaseError( + `We cannot infer your build target from a non-standard NODE_ENV. Please set the FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable. Valid values are: ${validOptions.join( + ", " + )}` + ); + } + } else if (purpose !== "serve") { + return "production"; + } else { + return "development"; + } +} From 7ed62f31df311043c5c0d3fe03198a5c63aa3e93 Mon Sep 17 00:00:00 2001 From: egilmorez Date: Tue, 23 May 2023 08:52:28 -0700 Subject: [PATCH 022/320] Tweaking some text string formatting as a follow-up to PR 5867. (#5876) * Tweaking some text string formatting as a follow-up to PR 5867. * Removing stray backtick. * Platform agnosticizing our usage of 'max instances.' --- src/gcp/cloudfunctionsv2.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gcp/cloudfunctionsv2.ts b/src/gcp/cloudfunctionsv2.ts index 73cada4acc5..4cef621da1a 100644 --- a/src/gcp/cloudfunctionsv2.ts +++ b/src/gcp/cloudfunctionsv2.ts @@ -245,7 +245,7 @@ function functionsOpLogReject(func: InputCloudFunction, type: string, err: any): utils.logLabeledWarning( "functions", `Your current project quotas don't allow for the current max instances setting of ${maxInstances}. ` + - "Either reduce this function's maxInstances, or request a quota increase on the underlying Cloud Run service " + + "Either reduce this function's maximum instances, or request a quota increase on the underlying Cloud Run service " + "at https://cloud.google.com/run/quotas." ); const suggestedFix = func.buildConfig.runtime.startsWith("python") @@ -269,7 +269,7 @@ function functionsOpLogReject(func: InputCloudFunction, type: string, err: any): ) { utils.logLabeledWarning( "functions", - `Since this is your first time using functions v2, we need a little bit longer to finish setting everything up, please retry the deployment in a few minutes.` + `Since this is your first time using 2nd gen functions, we need a little bit longer to finish setting everything up. Retry the deployment in a few minutes.` ); } utils.logLabeledWarning( From a6657dffa2e2a8644f6ccbb1cfbc311f77da0426 Mon Sep 17 00:00:00 2001 From: Chalo Salvador Date: Tue, 23 May 2023 19:35:02 +0200 Subject: [PATCH 023/320] Fix Vite js-sdk auto init (#5610) Co-authored-by: James Daniels --- CHANGELOG.md | 1 + src/frameworks/index.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33d60ee9611..3eaa6c1479f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,4 +5,5 @@ - Multi-page applications that are fully staticly rendered are no longer treated as PWAs. (#5716) - Add fast dev-mode support for devlopers using Nuxt v2. (#5716) - Respect `ssr: false` and `baseURL` when using Nuxt. (#5716) +- Fix bug where JS SDK auto-init was not working for Vite while in dev-mode (#5610). - Respect `FIREBASE_FRAMEWORKS_BUILD_TARGET` environment variable to override the default build target (#5572). diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index bd7ae7fe513..713bd48b5fe 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -538,7 +538,7 @@ ${ const sameSite = "Strict"; const path = `/`; config.headers.push({ - source: "**/*.js", + source: "**/*.[jt]s", headers: [ { key: "Set-Cookie", From 4c5d8c9b0edd7e70fa1d36ab4121ae20be566913 Mon Sep 17 00:00:00 2001 From: joehan Date: Tue, 23 May 2023 10:59:24 -0700 Subject: [PATCH 024/320] Adding package-lock.json to standalone/ (#5882) --- standalone/package-lock.json | 10646 +++++++++++++++++++++++++++++++++ 1 file changed, 10646 insertions(+) create mode 100644 standalone/package-lock.json diff --git a/standalone/package-lock.json b/standalone/package-lock.json new file mode 100644 index 00000000000..49c06aec91a --- /dev/null +++ b/standalone/package-lock.json @@ -0,0 +1,10646 @@ +{ + "name": "firepit", + "version": "1.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "firepit", + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "chalk": "^2.4.2", + "npm": "^6.10.2", + "shelljs": "^0.8.3", + "shx": "^0.3.2", + "user-home": "^2.0.0" + }, + "devDependencies": { + "pkg": "^5.7.0", + "prettier": "^1.15.3" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", + "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/into-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", + "dev": true, + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/jsesc": { + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multistream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "once": "^1.4.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/multistream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "node_modules/node-abi": { + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.40.0.tgz", + "integrity": "sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/npm": { + "version": "6.14.18", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.18.tgz", + "integrity": "sha512-p3SjqSchSuNQUqbJBgwdv0L3O6bKkaSfQrQzJsskNpNKLg0g37c5xTXFV0SqTlX9GWvoGxBELVJMRWq0J8oaLA==", + "bundleDependencies": [ + "abbrev", + "ansicolors", + "ansistyles", + "aproba", + "archy", + "bin-links", + "bluebird", + "byte-size", + "cacache", + "call-limit", + "chownr", + "ci-info", + "cli-columns", + "cli-table3", + "cmd-shim", + "columnify", + "config-chain", + "debuglog", + "detect-indent", + "detect-newline", + "dezalgo", + "editor", + "figgy-pudding", + "find-npm-prefix", + "fs-vacuum", + "fs-write-stream-atomic", + "gentle-fs", + "glob", + "graceful-fs", + "has-unicode", + "hosted-git-info", + "iferr", + "imurmurhash", + "infer-owner", + "inflight", + "inherits", + "ini", + "init-package-json", + "is-cidr", + "json-parse-better-errors", + "JSONStream", + "lazy-property", + "libcipm", + "libnpm", + "libnpmaccess", + "libnpmhook", + "libnpmorg", + "libnpmsearch", + "libnpmteam", + "libnpx", + "lock-verify", + "lockfile", + "lodash._baseindexof", + "lodash._baseuniq", + "lodash._bindcallback", + "lodash._cacheindexof", + "lodash._createcache", + "lodash._getnative", + "lodash.clonedeep", + "lodash.restparam", + "lodash.union", + "lodash.uniq", + "lodash.without", + "lru-cache", + "meant", + "mississippi", + "mkdirp", + "move-concurrently", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-cache-filename", + "npm-install-checks", + "npm-lifecycle", + "npm-package-arg", + "npm-packlist", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "once", + "opener", + "osenv", + "pacote", + "path-is-inside", + "promise-inflight", + "qrcode-terminal", + "query-string", + "qw", + "read-cmd-shim", + "read-installed", + "read-package-json", + "read-package-tree", + "read", + "readable-stream", + "readdir-scoped-modules", + "request", + "retry", + "rimraf", + "safe-buffer", + "semver", + "sha", + "slide", + "sorted-object", + "sorted-union-stream", + "ssri", + "stringify-package", + "tar", + "text-table", + "tiny-relative-date", + "uid-number", + "umask", + "unique-filename", + "unpipe", + "update-notifier", + "uuid", + "validate-npm-package-license", + "validate-npm-package-name", + "which", + "worker-farm", + "write-file-atomic" + ], + "dependencies": { + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "^2.0.0", + "archy": "~1.0.0", + "bin-links": "^1.1.8", + "bluebird": "^3.7.2", + "byte-size": "^5.0.1", + "cacache": "^12.0.4", + "call-limit": "^1.1.1", + "chownr": "^1.1.4", + "ci-info": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.1", + "cmd-shim": "^3.0.3", + "columnify": "~1.5.4", + "config-chain": "^1.1.13", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "^1.0.4", + "editor": "~1.0.0", + "figgy-pudding": "^3.5.2", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.3.1", + "glob": "^7.2.3", + "graceful-fs": "^4.2.10", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.8.9", + "iferr": "^1.0.2", + "imurmurhash": "*", + "infer-owner": "^1.0.4", + "inflight": "~1.0.6", + "inherits": "^2.0.4", + "ini": "^1.3.8", + "init-package-json": "^1.10.3", + "is-cidr": "^3.1.1", + "json-parse-better-errors": "^1.0.2", + "JSONStream": "^1.3.5", + "lazy-property": "~1.0.0", + "libcipm": "^4.0.8", + "libnpm": "^3.0.1", + "libnpmaccess": "^3.0.2", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "libnpx": "^10.2.4", + "lock-verify": "^2.2.2", + "lockfile": "^1.0.4", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^5.1.1", + "meant": "^1.0.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.6", + "move-concurrently": "^1.0.1", + "node-gyp": "^5.1.1", + "nopt": "^4.0.3", + "normalize-package-data": "^2.5.0", + "npm-audit-report": "^1.3.3", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "^3.0.2", + "npm-lifecycle": "^3.1.5", + "npm-package-arg": "^6.1.1", + "npm-packlist": "^1.4.8", + "npm-pick-manifest": "^3.0.2", + "npm-profile": "^4.0.4", + "npm-registry-fetch": "^4.0.7", + "npm-user-validate": "^1.0.1", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.2", + "osenv": "^0.1.5", + "pacote": "^9.5.12", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.14.1", + "qw": "^1.0.2", + "read": "~1.0.7", + "read-cmd-shim": "^1.0.5", + "read-installed": "~4.0.3", + "read-package-json": "^2.1.2", + "read-package-tree": "^5.3.1", + "readable-stream": "^3.6.0", + "readdir-scoped-modules": "^1.1.0", + "request": "^2.88.2", + "retry": "^0.12.0", + "rimraf": "^2.7.1", + "safe-buffer": "^5.2.1", + "semver": "^5.7.1", + "sha": "^3.0.0", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.2", + "stringify-package": "^1.0.1", + "tar": "^4.4.19", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "^1.1.1", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.4.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.7.0", + "write-file-atomic": "^2.4.3" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "6 >=6.2.0 || 8 || >=9.3.0" + } + }, + "node_modules/npm/node_modules/@iarna/cli": { + "version": "2.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.2", + "signal-exit": "^3.0.2" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "1.1.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/agent-base": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/npm/node_modules/agentkeepalive": { + "version": "3.5.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/npm/node_modules/ansi-align": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^2.0.0" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "3.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/ansicolors": { + "version": "0.3.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ansistyles": { + "version": "0.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "1.1.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/npm/node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/are-we-there-yet/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/are-we-there-yet/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/asap": { + "version": "2.0.6", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/asn1": { + "version": "0.2.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/npm/node_modules/assert-plus": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/asynckit": { + "version": "0.4.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/aws-sign2": { + "version": "0.7.0", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/aws4": { + "version": "1.11.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/npm/node_modules/bin-links": { + "version": "1.1.8", + "inBundle": true, + "license": "Artistic-2.0", + "dependencies": { + "bluebird": "^3.5.3", + "cmd-shim": "^3.0.0", + "gentle-fs": "^2.3.0", + "graceful-fs": "^4.1.15", + "npm-normalize-package-bin": "^1.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "node_modules/npm/node_modules/bluebird": { + "version": "3.7.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/boxen": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "1.1.11", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm/node_modules/buffer-from": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/builtins": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/byline": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/byte-size": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "12.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/npm/node_modules/call-limit": { + "version": "1.1.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/camelcase": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/capture-stack-trace": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/caseless": { + "version": "0.12.0", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/chalk": { + "version": "2.4.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "1.1.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/ci-info": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "2.0.10", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/cli-boxes": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "3.1.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/cli-table3": { + "version": "0.5.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/npm/node_modules/cliui": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/npm/node_modules/cliui/node_modules/ansi-regex": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/cliui/node_modules/string-width": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cliui/node_modules/strip-ansi": { + "version": "5.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "3.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "node_modules/npm/node_modules/code-point-at": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "1.9.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "^1.1.1" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/colors": { + "version": "1.3.3", + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/npm/node_modules/columnify": { + "version": "1.5.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "node_modules/npm/node_modules/combined-stream": { + "version": "1.0.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/npm/node_modules/concat-map": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/concat-stream": { + "version": "1.6.2", + "engines": [ + "node >= 0.8" + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/npm/node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/concat-stream/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/concat-stream/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/config-chain": { + "version": "1.1.13", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/npm/node_modules/configstore": { + "version": "3.1.5", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^4.2.1", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/console-control-strings": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/copy-concurrently": { + "version": "1.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "node_modules/npm/node_modules/copy-concurrently/node_modules/aproba": { + "version": "1.2.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/copy-concurrently/node_modules/iferr": { + "version": "0.1.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/core-util-is": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/create-error-class": { + "version": "3.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "capture-stack-trace": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/cross-spawn": { + "version": "5.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/lru-cache": { + "version": "4.1.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/yallist": { + "version": "2.1.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/crypto-random-string": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/cyclist": { + "version": "0.2.2", + "inBundle": true + }, + "node_modules/npm/node_modules/dashdash": { + "version": "1.14.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/debuglog": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/decamelize": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/decode-uri-component": { + "version": "0.2.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/npm/node_modules/deep-extend": { + "version": "0.6.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/npm/node_modules/define-properties": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/delayed-stream": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/npm/node_modules/delegates": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/detect-indent": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/detect-newline": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/dezalgo": { + "version": "1.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/dot-prop": { + "version": "4.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/dotenv": { + "version": "5.0.1", + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.6.0" + } + }, + "node_modules/npm/node_modules/duplexer3": { + "version": "0.1.4", + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npm/node_modules/duplexify": { + "version": "3.6.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/npm/node_modules/duplexify/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/duplexify/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/duplexify/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/duplexify/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ecc-jsbn": { + "version": "0.1.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/npm/node_modules/editor": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "7.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.12", + "inBundle": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "~0.4.13" + } + }, + "node_modules/npm/node_modules/end-of-stream": { + "version": "1.4.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "1.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/errno": { + "version": "0.1.7", + "inBundle": true, + "license": "MIT", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/npm/node_modules/es-abstract": { + "version": "1.12.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/es-to-primitive": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/es6-promise": { + "version": "4.2.8", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/es6-promisify": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/npm/node_modules/escape-string-regexp": { + "version": "1.0.5", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npm/node_modules/execa": { + "version": "0.7.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/execa/node_modules/get-stream": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/extend": { + "version": "3.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/extsprintf": { + "version": "1.3.0", + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fast-json-stable-stringify": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/figgy-pudding": { + "version": "3.5.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/filter-obj": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/find-npm-prefix": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/flush-write-stream": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "node_modules/npm/node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/flush-write-stream/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/flush-write-stream/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/flush-write-stream/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/forever-agent": { + "version": "0.6.1", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/form-data": { + "version": "2.3.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/npm/node_modules/from2": { + "version": "2.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/npm/node_modules/from2/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/from2/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/from2/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "1.2.7", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/npm/node_modules/fs-minipass/node_modules/minipass": { + "version": "2.9.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/npm/node_modules/fs-vacuum": { + "version": "1.2.10", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/npm/node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/iferr": { + "version": "0.1.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/fs-write-stream-atomic/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/fs.realpath": { + "version": "1.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/gauge": { + "version": "2.7.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/npm/node_modules/gauge/node_modules/aproba": { + "version": "1.2.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/genfun": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/gentle-fs": { + "version": "2.3.1", + "inBundle": true, + "license": "Artistic-2.0", + "dependencies": { + "aproba": "^1.1.2", + "chownr": "^1.1.2", + "cmd-shim": "^3.0.3", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "infer-owner": "^1.0.4", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" + } + }, + "node_modules/npm/node_modules/gentle-fs/node_modules/aproba": { + "version": "1.2.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/gentle-fs/node_modules/iferr": { + "version": "0.1.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/get-caller-file": { + "version": "2.0.5", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/npm/node_modules/get-stream": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/getpass": { + "version": "0.1.7", + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "7.2.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/global-dirs": { + "version": "0.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/got": { + "version": "6.7.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/got/node_modules/get-stream": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.10", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/har-schema": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/har-validator": { + "version": "5.1.5", + "deprecated": "this library is no longer supported", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/npm/node_modules/har-validator/node_modules/fast-deep-equal": { + "version": "3.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/has": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/npm/node_modules/has-flag": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/has-symbols": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "2.8.9", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "3.8.1", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "4", + "debug": "3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/npm/node_modules/http-signature": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "2.2.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/npm/node_modules/humanize-ms": { + "version": "1.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.4.23", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/iferr": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "3.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/npm/node_modules/import-lazy": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/infer-owner": { + "version": "1.0.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/inflight": { + "version": "1.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/inherits": { + "version": "2.0.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/ini": { + "version": "1.3.8", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "1.10.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/npm/node_modules/ip": { + "version": "1.1.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/is-callable": { + "version": "1.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/is-ci": { + "version": "1.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ci-info": "^1.5.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/npm/node_modules/is-ci/node_modules/ci-info": { + "version": "1.6.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "3.1.1", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^2.0.10" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/is-date-object": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/is-installed-globally": { + "version": "0.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/is-npm": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/is-obj": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/is-path-inside": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/is-redirect": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/is-regex": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/is-retry-allowed": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/is-stream": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/is-symbol": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/is-typedarray": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/isarray": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/isstream": { + "version": "0.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/jsbn": { + "version": "0.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-parse-better-errors": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-schema": { + "version": "0.4.0", + "inBundle": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/npm/node_modules/json-stringify-safe": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/JSONStream": { + "version": "1.3.5", + "inBundle": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/jsprim": { + "version": "1.4.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/npm/node_modules/latest-version": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "package-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/lazy-property": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libcipm": { + "version": "4.0.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "ini": "^1.3.5", + "lock-verify": "^2.1.0", + "mkdirp": "^0.5.1", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "pacote": "^9.1.0", + "read-package-json": "^2.0.13", + "rimraf": "^2.6.2", + "worker-farm": "^1.6.0" + } + }, + "node_modules/npm/node_modules/libnpm": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.3", + "find-npm-prefix": "^1.0.2", + "libnpmaccess": "^3.0.2", + "libnpmconfig": "^1.2.1", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmpublish": "^1.1.2", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "lock-verify": "^2.0.2", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "npm-profile": "^4.0.2", + "npm-registry-fetch": "^4.0.0", + "npmlog": "^4.1.2", + "pacote": "^9.5.3", + "read-package-json": "^2.0.13", + "stringify-package": "^1.0.0" + } + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "get-stream": "^4.0.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "node_modules/npm/node_modules/libnpmconfig": { + "version": "1.2.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "figgy-pudding": "^3.5.1", + "find-up": "^3.0.0", + "ini": "^1.3.5" + } + }, + "node_modules/npm/node_modules/libnpmconfig/node_modules/find-up": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/libnpmconfig/node_modules/locate-path": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/libnpmconfig/node_modules/p-limit": { + "version": "2.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/libnpmconfig/node_modules/p-locate": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/libnpmconfig/node_modules/p-try": { + "version": "2.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "5.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "1.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "lodash.clonedeep": "^4.5.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0", + "semver": "^5.5.1", + "ssri": "^6.0.1" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "2.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "node_modules/npm/node_modules/libnpx": { + "version": "10.2.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^14.2.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/lock-verify": { + "version": "2.2.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@iarna/cli": "^2.1.0", + "npm-package-arg": "^6.1.0", + "semver": "^5.4.1" + }, + "bin": { + "lock-verify": "cli.js" + } + }, + "node_modules/npm/node_modules/lockfile": { + "version": "1.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "signal-exit": "^3.0.2" + } + }, + "node_modules/npm/node_modules/lodash._baseindexof": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash._baseuniq": { + "version": "4.6.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "node_modules/npm/node_modules/lodash._bindcallback": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash._cacheindexof": { + "version": "3.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash._createcache": { + "version": "3.1.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "lodash._getnative": "^3.0.0" + } + }, + "node_modules/npm/node_modules/lodash._createset": { + "version": "4.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash._getnative": { + "version": "3.9.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash._root": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash.clonedeep": { + "version": "4.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash.restparam": { + "version": "3.6.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash.union": { + "version": "4.6.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash.uniq": { + "version": "4.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lodash.without": { + "version": "4.4.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/lowercase-keys": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "5.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/npm/node_modules/make-dir": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "5.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "node_modules/npm/node_modules/meant": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mime-db": { + "version": "1.35.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/mime-types": { + "version": "2.1.19", + "inBundle": true, + "license": "MIT", + "dependencies": { + "mime-db": "~1.35.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "3.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/minimist": { + "version": "1.2.6", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/minizlib": { + "version": "1.3.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "2.9.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/npm/node_modules/mississippi": { + "version": "3.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "0.5.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/npm/node_modules/move-concurrently": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/npm/node_modules/move-concurrently/node_modules/aproba": { + "version": "1.2.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "0.0.7", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/node-fetch-npm": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "5.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "4.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "2.5.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/npm/node_modules/normalize-package-data/node_modules/resolve": { + "version": "1.10.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "1.3.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "cli-table3": "^0.5.0", + "console-control-strings": "^1.1.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "1.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm/node_modules/npm-cache-filename": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "3.0.2", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "node_modules/npm/node_modules/npm-lifecycle": { + "version": "3.1.5", + "inBundle": true, + "license": "Artistic-2.0", + "dependencies": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "node_modules/npm/node_modules/npm-logical-tree": { + "version": "1.2.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "6.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "1.4.8", + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "4.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.1.2 || 2", + "figgy-pudding": "^3.4.1", + "npm-registry-fetch": "^4.0.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "4.0.7", + "inBundle": true, + "license": "ISC", + "dependencies": { + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "JSONStream": "^1.3.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/npm-run-path": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "1.0.1", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/npmlog": { + "version": "4.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/npm/node_modules/number-is-nan": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/oauth-sign": { + "version": "0.9.0", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/object-assign": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/object-keys": { + "version": "1.0.12", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/object.getownpropertydescriptors": { + "version": "2.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/npm/node_modules/once": { + "version": "1.4.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/opener": { + "version": "1.5.2", + "inBundle": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/npm/node_modules/os-homedir": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/os-tmpdir": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/osenv": { + "version": "0.1.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/npm/node_modules/p-finally": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/package-json": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "9.5.12", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-normalize-package-bin": "^1.0.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + } + }, + "node_modules/npm/node_modules/pacote/node_modules/minipass": { + "version": "2.9.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/npm/node_modules/parallel-transform": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/npm/node_modules/parallel-transform/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/parallel-transform/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/parallel-transform/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/parallel-transform/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/path-exists": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/path-is-absolute": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/path-is-inside": { + "version": "1.0.2", + "inBundle": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/npm/node_modules/path-key": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/path-parse": { + "version": "1.0.7", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/performance-now": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/pify": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/prepend-http": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/process-nextick-args": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/npm/node_modules/promise-retry/node_modules/retry": { + "version": "0.10.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "0.3.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "1" + } + }, + "node_modules/npm/node_modules/proto-list": { + "version": "1.2.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/protoduck": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "genfun": "^5.0.0" + } + }, + "node_modules/npm/node_modules/prr": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/pseudomap": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/psl": { + "version": "1.9.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/pump": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/npm/node_modules/pumpify": { + "version": "1.5.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/npm/node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/qs": { + "version": "6.5.3", + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/npm/node_modules/query-string": { + "version": "6.14.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/qw": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/rc": { + "version": "1.2.8", + "inBundle": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "1.0.7", + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "1.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/npm/node_modules/read-installed": { + "version": "4.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/npm/node_modules/read-package-json": { + "version": "2.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "node_modules/npm/node_modules/read-package-tree": { + "version": "5.3.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "node_modules/npm/node_modules/readable-stream": { + "version": "3.6.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/npm/node_modules/registry-auth-token": { + "version": "3.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/npm/node_modules/registry-url": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/request": { + "version": "2.88.2", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/require-directory": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/require-main-filename": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/resolve-from": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/rimraf": { + "version": "2.7.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/npm/node_modules/run-queue": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.1.1" + } + }, + "node_modules/npm/node_modules/run-queue/node_modules/aproba": { + "version": "1.2.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/semver": { + "version": "5.7.1", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm/node_modules/semver-diff": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "semver": "^5.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/sha": { + "version": "3.0.0", + "inBundle": true, + "license": "(BSD-2-Clause OR MIT)", + "dependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/npm/node_modules/shebang-command": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/shebang-regex": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/slide": { + "version": "1.1.6", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.3.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + }, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "4.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "4.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/npm/node_modules/sorted-object": { + "version": "2.0.1", + "inBundle": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/npm/node_modules/sorted-union-stream": { + "version": "2.1.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + } + }, + "node_modules/npm/node_modules/sorted-union-stream/node_modules/from2": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + } + }, + "node_modules/npm/node_modules/sorted-union-stream/node_modules/isarray": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/sorted-union-stream/node_modules/readable-stream": { + "version": "1.1.14", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/npm/node_modules/sorted-union-stream/node_modules/string_decoder": { + "version": "0.10.31", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.0.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.1.0", + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.5", + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/split-on-first": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/sshpk": { + "version": "1.17.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ssri": { + "version": "6.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/npm/node_modules/stream-each": { + "version": "1.2.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/npm/node_modules/stream-iterate": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + } + }, + "node_modules/npm/node_modules/stream-iterate/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/stream-iterate/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/stream-iterate/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/stream-iterate/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/stream-shift": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/strict-uri-encode": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/string_decoder": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/npm/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/string-width": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/stringify-package": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/strip-eof": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/strip-json-comments": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "5.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "4.4.19", + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minipass": { + "version": "2.9.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/npm/node_modules/tar/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tar/node_modules/yallist": { + "version": "3.1.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/term-size": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "execa": "^0.7.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/through": { + "version": "2.3.8", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/through2": { + "version": "2.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + }, + "node_modules/npm/node_modules/through2/node_modules/readable-stream": { + "version": "2.3.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/npm/node_modules/through2/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/through2/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/timed-out": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tough-cookie": { + "version": "2.5.0", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/tough-cookie/node_modules/punycode": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/tunnel-agent": { + "version": "0.6.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/tweetnacl": { + "version": "0.14.5", + "inBundle": true, + "license": "Unlicense" + }, + "node_modules/npm/node_modules/typedarray": { + "version": "0.0.6", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/uid-number": { + "version": "0.0.6", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/umask": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "1.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/npm/node_modules/unique-string": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/unpipe": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/npm/node_modules/unzip-response": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/update-notifier": { + "version": "2.5.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/uri-js": { + "version": "4.4.1", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/npm/node_modules/uri-js/node_modules/punycode": { + "version": "2.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/url-parse-lax": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "prepend-http": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/util-extend": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/util-promisify": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/npm/node_modules/uuid": { + "version": "3.4.0", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "inBundle": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/npm/node_modules/verror": { + "version": "1.10.0", + "engines": [ + "node >=0.6.0" + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npm/node_modules/which": { + "version": "1.3.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npm/node_modules/which-module": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2" + } + }, + "node_modules/npm/node_modules/wide-align/node_modules/string-width": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/widest-line": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/worker-farm": { + "version": "1.7.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "errno": "~0.1.7" + } + }, + "node_modules/npm/node_modules/wrap-ansi": { + "version": "5.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "5.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/wrappy": { + "version": "1.0.2", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "2.4.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/npm/node_modules/xdg-basedir": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/xtend": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/npm/node_modules/y18n": { + "version": "4.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/yallist": { + "version": "3.0.3", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/yargs": { + "version": "14.2.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + } + }, + "node_modules/npm/node_modules/yargs-parser": { + "version": "15.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/npm/node_modules/yargs-parser/node_modules/camelcase": { + "version": "5.3.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/ansi-regex": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/find-up": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/locate-path": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/p-locate": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/p-try": { + "version": "2.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/string-width": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/yargs/node_modules/strip-ansi": { + "version": "5.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.1.tgz", + "integrity": "sha512-CjBWtFStCfIiT4Bde9QpJy0KeH19jCfwZRJqHFDFXfhUklCx8JoFmMj3wgnEYIwGmZVNkhsStPHEOnrtrQhEXA==", + "dev": true, + "dependencies": { + "@babel/generator": "7.18.2", + "@babel/parser": "7.18.4", + "@babel/types": "7.19.0", + "chalk": "^4.1.2", + "fs-extra": "^9.1.0", + "globby": "^11.1.0", + "into-stream": "^6.0.0", + "is-core-module": "2.9.0", + "minimist": "^1.2.6", + "multistream": "^4.1.0", + "pkg-fetch": "3.4.2", + "prebuild-install": "7.1.1", + "resolve": "^1.22.0", + "stream-meter": "^1.0.4" + }, + "bin": { + "pkg": "lib-es5/bin.js" + }, + "peerDependencies": { + "node-notifier": ">=9.0.1" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/pkg-fetch": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.4.2.tgz", + "integrity": "sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "fs-extra": "^9.1.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.6", + "progress": "^2.0.3", + "semver": "^7.3.5", + "tar-fs": "^2.1.1", + "yargs": "^16.2.0" + }, + "bin": { + "pkg-fetch": "lib-es5/bin.js" + } + }, + "node_modules/pkg-fetch/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pkg-fetch/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/pkg-fetch/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pkg-fetch/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/pkg-fetch/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-fetch/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pkg/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/pkg/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pkg/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/pkg/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve/node_modules/is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "dependencies": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stream-meter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", + "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", + "dev": true, + "dependencies": { + "readable-stream": "^2.1.4" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ==", + "dependencies": { + "os-homedir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + } + }, + "dependencies": { + "@babel/generator": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "dev": true, + "requires": { + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-string-parser": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", + "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/parser": { + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", + "dev": true + }, + "@babel/types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", + "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "into-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", + "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", + "dev": true, + "requires": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + } + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multistream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", + "dev": true, + "requires": { + "once": "^1.4.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "node-abi": { + "version": "3.40.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.40.0.tgz", + "integrity": "sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "npm": { + "version": "6.14.18", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.18.tgz", + "integrity": "sha512-p3SjqSchSuNQUqbJBgwdv0L3O6bKkaSfQrQzJsskNpNKLg0g37c5xTXFV0SqTlX9GWvoGxBELVJMRWq0J8oaLA==", + "requires": { + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "^2.0.0", + "archy": "~1.0.0", + "bin-links": "^1.1.8", + "bluebird": "^3.7.2", + "byte-size": "^5.0.1", + "cacache": "^12.0.4", + "call-limit": "^1.1.1", + "chownr": "^1.1.4", + "ci-info": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.5.1", + "cmd-shim": "^3.0.3", + "columnify": "~1.5.4", + "config-chain": "^1.1.13", + "debuglog": "*", + "detect-indent": "~5.0.0", + "detect-newline": "^2.1.0", + "dezalgo": "^1.0.4", + "editor": "~1.0.0", + "figgy-pudding": "^3.5.2", + "find-npm-prefix": "^1.0.2", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "gentle-fs": "^2.3.1", + "glob": "^7.2.3", + "graceful-fs": "^4.2.10", + "has-unicode": "~2.0.1", + "hosted-git-info": "^2.8.9", + "iferr": "^1.0.2", + "imurmurhash": "*", + "infer-owner": "^1.0.4", + "inflight": "~1.0.6", + "inherits": "^2.0.4", + "ini": "^1.3.8", + "init-package-json": "^1.10.3", + "is-cidr": "^3.1.1", + "json-parse-better-errors": "^1.0.2", + "JSONStream": "^1.3.5", + "lazy-property": "~1.0.0", + "libcipm": "^4.0.8", + "libnpm": "^3.0.1", + "libnpmaccess": "^3.0.2", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "libnpx": "^10.2.4", + "lock-verify": "^2.2.2", + "lockfile": "^1.0.4", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "^5.1.1", + "meant": "^1.0.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.6", + "move-concurrently": "^1.0.1", + "node-gyp": "^5.1.1", + "nopt": "^4.0.3", + "normalize-package-data": "^2.5.0", + "npm-audit-report": "^1.3.3", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "^3.0.2", + "npm-lifecycle": "^3.1.5", + "npm-package-arg": "^6.1.1", + "npm-packlist": "^1.4.8", + "npm-pick-manifest": "^3.0.2", + "npm-profile": "^4.0.4", + "npm-registry-fetch": "^4.0.7", + "npm-user-validate": "^1.0.1", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "^1.5.2", + "osenv": "^0.1.5", + "pacote": "^9.5.12", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "qrcode-terminal": "^0.12.0", + "query-string": "^6.14.1", + "qw": "^1.0.2", + "read": "~1.0.7", + "read-cmd-shim": "^1.0.5", + "read-installed": "~4.0.3", + "read-package-json": "^2.1.2", + "read-package-tree": "^5.3.1", + "readable-stream": "^3.6.0", + "readdir-scoped-modules": "^1.1.0", + "request": "^2.88.2", + "retry": "^0.12.0", + "rimraf": "^2.7.1", + "safe-buffer": "^5.2.1", + "semver": "^5.7.1", + "sha": "^3.0.0", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "^6.0.2", + "stringify-package": "^1.0.1", + "tar": "^4.4.19", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "^1.1.1", + "unpipe": "~1.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.4.0", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^1.3.1", + "worker-farm": "^1.7.0", + "write-file-atomic": "^2.4.3" + }, + "dependencies": { + "@iarna/cli": { + "version": "2.1.0", + "bundled": true, + "requires": { + "glob": "^7.1.2", + "signal-exit": "^3.0.2" + } + }, + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "agent-base": { + "version": "4.3.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "bundled": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "asap": { + "version": "2.0.6", + "bundled": true + }, + "asn1": { + "version": "0.2.6", + "bundled": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true + }, + "aws4": { + "version": "1.11.0", + "bundled": true + }, + "balanced-match": { + "version": "1.0.2", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bin-links": { + "version": "1.1.8", + "bundled": true, + "requires": { + "bluebird": "^3.5.3", + "cmd-shim": "^3.0.0", + "gentle-fs": "^2.3.0", + "graceful-fs": "^4.1.15", + "npm-normalize-package-bin": "^1.0.0", + "write-file-atomic": "^2.3.0" + } + }, + "bluebird": { + "version": "3.7.2", + "bundled": true + }, + "boxen": { + "version": "1.3.0", + "bundled": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.0.0", + "bundled": true + }, + "builtins": { + "version": "1.0.3", + "bundled": true + }, + "byline": { + "version": "5.0.0", + "bundled": true + }, + "byte-size": { + "version": "5.0.1", + "bundled": true + }, + "cacache": { + "version": "12.0.4", + "bundled": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "call-limit": { + "version": "1.1.1", + "bundled": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true + }, + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.1.4", + "bundled": true + }, + "ci-info": { + "version": "2.0.0", + "bundled": true + }, + "cidr-regex": { + "version": "2.0.10", + "bundled": true, + "requires": { + "ip-regex": "^2.1.0" + } + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true + }, + "cli-columns": { + "version": "3.1.2", + "bundled": true, + "requires": { + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" + } + }, + "cli-table3": { + "version": "0.5.1", + "bundled": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, + "cliui": { + "version": "5.0.0", + "bundled": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "bundled": true + }, + "cmd-shim": { + "version": "3.0.3", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true + }, + "colors": { + "version": "1.3.3", + "bundled": true, + "optional": true + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "bundled": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "config-chain": { + "version": "1.1.13", + "bundled": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "3.1.5", + "bundled": true, + "requires": { + "dot-prop": "^4.2.1", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "copy-concurrently": { + "version": "1.0.5", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "crypto-random-string": { + "version": "1.0.0", + "bundled": true + }, + "cyclist": { + "version": "0.2.2", + "bundled": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "decode-uri-component": { + "version": "0.2.2", + "bundled": true + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true + }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-properties": { + "version": "1.1.3", + "bundled": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true + }, + "detect-newline": { + "version": "2.1.0", + "bundled": true + }, + "dezalgo": { + "version": "1.0.4", + "bundled": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "dot-prop": { + "version": "4.2.1", + "bundled": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "5.0.1", + "bundled": true + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true + }, + "duplexify": { + "version": "3.6.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "bundled": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "emoji-regex": { + "version": "7.0.3", + "bundled": true + }, + "encoding": { + "version": "0.1.12", + "bundled": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "env-paths": { + "version": "2.2.1", + "bundled": true + }, + "err-code": { + "version": "1.1.2", + "bundled": true + }, + "errno": { + "version": "0.1.7", + "bundled": true, + "requires": { + "prr": "~1.0.1" + } + }, + "es-abstract": { + "version": "1.12.0", + "bundled": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "bundled": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "bundled": true + }, + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.2", + "bundled": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "figgy-pudding": { + "version": "3.5.2", + "bundled": true + }, + "filter-obj": { + "version": "1.1.0", + "bundled": true + }, + "find-npm-prefix": { + "version": "1.0.2", + "bundled": true + }, + "flush-write-stream": { + "version": "1.0.3", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.3.3", + "bundled": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "fs-minipass": { + "version": "1.2.7", + "bundled": true, + "requires": { + "minipass": "^2.6.0" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "genfun": { + "version": "5.0.0", + "bundled": true + }, + "gentle-fs": { + "version": "2.3.1", + "bundled": true, + "requires": { + "aproba": "^1.1.2", + "chownr": "^1.1.2", + "cmd-shim": "^3.0.3", + "fs-vacuum": "^1.2.10", + "graceful-fs": "^4.1.11", + "iferr": "^0.1.5", + "infer-owner": "^1.0.4", + "mkdirp": "^0.5.1", + "path-is-inside": "^1.0.2", + "read-cmd-shim": "^1.0.1", + "slide": "^1.1.6" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "bundled": true + }, + "get-stream": { + "version": "4.1.0", + "bundled": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.3", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "global-dirs": { + "version": "0.1.1", + "bundled": true, + "requires": { + "ini": "^1.3.4" + } + }, + "got": { + "version": "6.7.1", + "bundled": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.2.10", + "bundled": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true + }, + "har-validator": { + "version": "5.1.5", + "bundled": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "bundled": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "bundled": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "bundled": true + } + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "has-symbols": { + "version": "1.0.0", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hosted-git-info": { + "version": "2.8.9", + "bundled": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "bundled": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + } + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "bundled": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "iferr": { + "version": "1.0.2", + "bundled": true + }, + "ignore-walk": { + "version": "3.0.3", + "bundled": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "infer-owner": { + "version": "1.0.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true + }, + "ini": { + "version": "1.3.8", + "bundled": true + }, + "init-package-json": { + "version": "1.10.3", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + } + }, + "ip": { + "version": "1.1.5", + "bundled": true + }, + "ip-regex": { + "version": "2.1.0", + "bundled": true + }, + "is-callable": { + "version": "1.1.4", + "bundled": true + }, + "is-ci": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ci-info": "^1.5.0" + }, + "dependencies": { + "ci-info": { + "version": "1.6.0", + "bundled": true + } + } + }, + "is-cidr": { + "version": "3.1.1", + "bundled": true, + "requires": { + "cidr-regex": "^2.0.10" + } + }, + "is-date-object": { + "version": "1.0.1", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "bundled": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "bundled": true + }, + "is-obj": { + "version": "1.0.1", + "bundled": true + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true + }, + "is-regex": { + "version": "1.0.4", + "bundled": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-retry-allowed": { + "version": "1.2.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "is-symbol": { + "version": "1.0.2", + "bundled": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "bundled": true + }, + "json-schema": { + "version": "0.4.0", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true + }, + "JSONStream": { + "version": "1.3.5", + "bundled": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "jsprim": { + "version": "1.4.2", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true + }, + "libcipm": { + "version": "4.0.8", + "bundled": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.5.1", + "find-npm-prefix": "^1.0.2", + "graceful-fs": "^4.1.11", + "ini": "^1.3.5", + "lock-verify": "^2.1.0", + "mkdirp": "^0.5.1", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "pacote": "^9.1.0", + "read-package-json": "^2.0.13", + "rimraf": "^2.6.2", + "worker-farm": "^1.6.0" + } + }, + "libnpm": { + "version": "3.0.1", + "bundled": true, + "requires": { + "bin-links": "^1.1.2", + "bluebird": "^3.5.3", + "find-npm-prefix": "^1.0.2", + "libnpmaccess": "^3.0.2", + "libnpmconfig": "^1.2.1", + "libnpmhook": "^5.0.3", + "libnpmorg": "^1.0.1", + "libnpmpublish": "^1.1.2", + "libnpmsearch": "^2.0.2", + "libnpmteam": "^1.0.2", + "lock-verify": "^2.0.2", + "npm-lifecycle": "^3.0.0", + "npm-logical-tree": "^1.2.1", + "npm-package-arg": "^6.1.0", + "npm-profile": "^4.0.2", + "npm-registry-fetch": "^4.0.0", + "npmlog": "^4.1.2", + "pacote": "^9.5.3", + "read-package-json": "^2.0.13", + "stringify-package": "^1.0.0" + } + }, + "libnpmaccess": { + "version": "3.0.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "get-stream": "^4.0.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmconfig": { + "version": "1.2.1", + "bundled": true, + "requires": { + "figgy-pudding": "^3.5.1", + "find-up": "^3.0.0", + "ini": "^1.3.5" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "bundled": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.2.0", + "bundled": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true + } + } + }, + "libnpmhook": { + "version": "5.0.3", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmorg": { + "version": "1.0.1", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmpublish": { + "version": "1.1.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "lodash.clonedeep": "^4.5.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-registry-fetch": "^4.0.0", + "semver": "^5.5.1", + "ssri": "^6.0.1" + } + }, + "libnpmsearch": { + "version": "2.0.2", + "bundled": true, + "requires": { + "figgy-pudding": "^3.5.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpmteam": { + "version": "1.0.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "figgy-pudding": "^3.4.1", + "get-stream": "^4.0.0", + "npm-registry-fetch": "^4.0.0" + } + }, + "libnpx": { + "version": "10.2.4", + "bundled": true, + "requires": { + "dotenv": "^5.0.1", + "npm-package-arg": "^6.0.0", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.0", + "update-notifier": "^2.3.0", + "which": "^1.3.0", + "y18n": "^4.0.0", + "yargs": "^14.2.3" + } + }, + "lock-verify": { + "version": "2.2.2", + "bundled": true, + "requires": { + "@iarna/cli": "^2.1.0", + "npm-package-arg": "^6.1.0", + "semver": "^5.4.1" + } + }, + "lockfile": { + "version": "1.0.4", + "bundled": true, + "requires": { + "signal-exit": "^3.0.2" + } + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._createset": { + "version": "4.0.3", + "bundled": true + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true + }, + "lowercase-keys": { + "version": "1.0.1", + "bundled": true + }, + "lru-cache": { + "version": "5.1.1", + "bundled": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "1.3.0", + "bundled": true, + "requires": { + "pify": "^3.0.0" + } + }, + "make-fetch-happen": { + "version": "5.0.2", + "bundled": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "meant": { + "version": "1.0.3", + "bundled": true + }, + "mime-db": { + "version": "1.35.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.19", + "bundled": true, + "requires": { + "mime-db": "~1.35.0" + } + }, + "minimatch": { + "version": "3.1.2", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "bundled": true + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "requires": { + "minipass": "^2.9.0" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "mississippi": { + "version": "3.0.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mkdirp": { + "version": "0.5.6", + "bundled": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true + } + } + }, + "ms": { + "version": "2.1.1", + "bundled": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "bundled": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-gyp": { + "version": "5.1.1", + "bundled": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" + } + }, + "nopt": { + "version": "4.0.3", + "bundled": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "resolve": { + "version": "1.10.0", + "bundled": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "npm-audit-report": { + "version": "1.3.3", + "bundled": true, + "requires": { + "cli-table3": "^0.5.0", + "console-control-strings": "^1.1.0" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "3.0.2", + "bundled": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-lifecycle": { + "version": "3.1.5", + "bundled": true, + "requires": { + "byline": "^5.0.0", + "graceful-fs": "^4.1.15", + "node-gyp": "^5.0.2", + "resolve-from": "^4.0.0", + "slide": "^1.1.6", + "uid-number": "0.0.6", + "umask": "^1.1.0", + "which": "^1.3.1" + } + }, + "npm-logical-tree": { + "version": "1.2.1", + "bundled": true + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true + }, + "npm-package-arg": { + "version": "6.1.1", + "bundled": true, + "requires": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-packlist": { + "version": "1.4.8", + "bundled": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "bundled": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "npm-profile": { + "version": "4.0.4", + "bundled": true, + "requires": { + "aproba": "^1.1.2 || 2", + "figgy-pudding": "^3.4.1", + "npm-registry-fetch": "^4.0.0" + } + }, + "npm-registry-fetch": { + "version": "4.0.7", + "bundled": true, + "requires": { + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "JSONStream": "^1.3.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "bundled": true + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.1", + "bundled": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.9.0", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "object-keys": { + "version": "1.0.12", + "bundled": true + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "bundled": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.2", + "bundled": true + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true + }, + "package-json": { + "version": "4.0.1", + "bundled": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "pacote": { + "version": "9.5.12", + "bundled": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-normalize-package-bin": "^1.0.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^3.0.0", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.10", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + } + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "path-exists": { + "version": "3.0.0", + "bundled": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true + }, + "path-parse": { + "version": "1.0.7", + "bundled": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true + }, + "pify": { + "version": "3.0.0", + "bundled": true + }, + "prepend-http": { + "version": "1.0.4", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "bundled": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1" + } + }, + "proto-list": { + "version": "1.2.4", + "bundled": true + }, + "protoduck": { + "version": "5.0.1", + "bundled": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "prr": { + "version": "1.0.1", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "psl": { + "version": "1.9.0", + "bundled": true + }, + "pump": { + "version": "3.0.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "bundled": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true + }, + "qs": { + "version": "6.5.3", + "bundled": true + }, + "query-string": { + "version": "6.14.1", + "bundled": true, + "requires": { + "decode-uri-component": "^0.2.0", + "filter-obj": "^1.1.0", + "split-on-first": "^1.0.0", + "strict-uri-encode": "^2.0.0" + } + }, + "qw": { + "version": "1.0.2", + "bundled": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "1.0.5", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + } + }, + "read-package-json": { + "version": "2.1.2", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "bundled": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "registry-auth-token": { + "version": "3.4.0", + "bundled": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "^1.0.1" + } + }, + "request": { + "version": "2.88.2", + "bundled": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true + }, + "require-main-filename": { + "version": "2.0.0", + "bundled": true + }, + "resolve-from": { + "version": "4.0.0", + "bundled": true + }, + "retry": { + "version": "0.12.0", + "bundled": true + }, + "rimraf": { + "version": "2.7.1", + "bundled": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "^1.1.1" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true + } + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "semver": { + "version": "5.7.1", + "bundled": true + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "requires": { + "semver": "^5.0.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "sha": { + "version": "3.0.0", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "smart-buffer": { + "version": "4.1.0", + "bundled": true + }, + "socks": { + "version": "2.3.3", + "bundled": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "bundled": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + } + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "bundled": true + }, + "split-on-first": { + "version": "1.1.0", + "bundled": true + }, + "sshpk": { + "version": "1.17.0", + "bundled": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.2", + "bundled": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stream-each": { + "version": "1.2.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true + }, + "strict-uri-encode": { + "version": "2.0.0", + "bundled": true + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "bundled": true + } + } + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "stringify-package": { + "version": "1.0.1", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar": { + "version": "4.4.19", + "bundled": true, + "requires": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "dependencies": { + "minipass": { + "version": "2.9.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true + } + } + }, + "term-size": { + "version": "1.2.0", + "bundled": true, + "requires": { + "execa": "^0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "bundled": true + } + } + } + } + }, + "timed-out": { + "version": "4.0.1", + "bundled": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true + }, + "tough-cookie": { + "version": "2.5.0", + "bundled": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "bundled": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true + }, + "update-notifier": { + "version": "2.5.0", + "bundled": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "bundled": true, + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "bundled": true + } + } + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "util-extend": { + "version": "1.0.3", + "bundled": true + }, + "util-promisify": { + "version": "2.1.0", + "bundled": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "uuid": { + "version": "3.4.0", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "requires": { + "string-width": "^1.0.2" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "widest-line": { + "version": "2.0.1", + "bundled": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "bundled": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "bundled": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "2.4.3", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + }, + "y18n": { + "version": "4.0.1", + "bundled": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true + }, + "yargs": { + "version": "14.2.3", + "bundled": true, + "requires": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true + }, + "find-up": { + "version": "3.0.0", + "bundled": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "bundled": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "15.0.1", + "bundled": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "bundled": true + } + } + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==" + }, + "p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pkg": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.1.tgz", + "integrity": "sha512-CjBWtFStCfIiT4Bde9QpJy0KeH19jCfwZRJqHFDFXfhUklCx8JoFmMj3wgnEYIwGmZVNkhsStPHEOnrtrQhEXA==", + "dev": true, + "requires": { + "@babel/generator": "7.18.2", + "@babel/parser": "7.18.4", + "@babel/types": "7.19.0", + "chalk": "^4.1.2", + "fs-extra": "^9.1.0", + "globby": "^11.1.0", + "into-stream": "^6.0.0", + "is-core-module": "2.9.0", + "minimist": "^1.2.6", + "multistream": "^4.1.0", + "pkg-fetch": "3.4.2", + "prebuild-install": "7.1.1", + "resolve": "^1.22.0", + "stream-meter": "^1.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "pkg-fetch": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.4.2.tgz", + "integrity": "sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "fs-extra": "^9.1.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.6", + "progress": "^2.0.3", + "semver": "^7.3.5", + "tar-fs": "^2.1.1", + "yargs": "^16.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "requires": { + "resolve": "^1.1.6" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "dependencies": { + "is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "requires": { + "has": "^1.0.3" + } + } + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "requires": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "stream-meter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", + "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", + "dev": true, + "requires": { + "readable-stream": "^2.1.4" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha512-KMWqdlOcjCYdtIJpicDSFBQ8nFwS2i9sslAd6f4+CBGcU4gist2REnr2fxj2YocvJFxSF3ZOHLYLVZnUxv4BZQ==", + "requires": { + "os-homedir": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + } + } +} From 7909fc6fd9ab7d5862a10d1fca929e009d1ff9e8 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 23 May 2023 11:22:51 -0700 Subject: [PATCH 025/320] Improves cleanup process when reloading emulated functions in debug mode. (#5878) Instead of spawning a new process that exposes the debugger endpoint, the Functions Emulator will attempt to explicitly kill the existing process before loading the function with the updated source code. Possible fix for https://github.com/firebase/firebase-tools/issues/5508, https://github.com/firebase/firebase-tools/issues/5653. --- CHANGELOG.md | 1 + src/emulator/functionsEmulator.ts | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eaa6c1479f..84037fcb430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,3 +7,4 @@ - Respect `ssr: false` and `baseURL` when using Nuxt. (#5716) - Fix bug where JS SDK auto-init was not working for Vite while in dev-mode (#5610). - Respect `FIREBASE_FRAMEWORKS_BUILD_TARGET` environment variable to override the default build target (#5572). +- Improves cleanup process when reloading emulated functions in debug mode. (#5878) diff --git a/src/emulator/functionsEmulator.ts b/src/emulator/functionsEmulator.ts index 78fd82d2711..f350d2d6d33 100644 --- a/src/emulator/functionsEmulator.ts +++ b/src/emulator/functionsEmulator.ts @@ -561,7 +561,12 @@ export class FunctionsEmulator implements EmulatorInstance { } // Before loading any triggers we need to make sure there are no 'stale' workers // in the pool that would cause us to run old code. - this.workerPools[emulatableBackend.codebase].refresh(); + if (this.debugMode) { + // Kill the workerPool. This should clean up all inspectors connected to the debug port. + this.workerPools[emulatableBackend.codebase].exit(); + } else { + this.workerPools[emulatableBackend.codebase].refresh(); + } // reset blocking functions config for reloads this.blockingFunctionsConfig = {}; From cbd92e87146f270c1954e76e42c0bce2041c7e41 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Tue, 23 May 2023 15:00:35 -0400 Subject: [PATCH 026/320] Allow web frameworks to target Node v20 (#5879) --- CHANGELOG.md | 1 + src/frameworks/constants.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84037fcb430..f19f1bfdec2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,3 +8,4 @@ - Fix bug where JS SDK auto-init was not working for Vite while in dev-mode (#5610). - Respect `FIREBASE_FRAMEWORKS_BUILD_TARGET` environment variable to override the default build target (#5572). - Improves cleanup process when reloading emulated functions in debug mode. (#5878) +- Allow Web Frameworks to target NodeJS v20. (#5879) diff --git a/src/frameworks/constants.ts b/src/frameworks/constants.ts index 592e5b9f870..1b424cb187c 100644 --- a/src/frameworks/constants.ts +++ b/src/frameworks/constants.ts @@ -32,7 +32,7 @@ export const FIREBASE_FUNCTIONS_VERSION = "^4.3.0"; export const FIREBASE_ADMIN_VERSION = "^11.0.1"; export const SHARP_VERSION = "^0.32.1"; export const NODE_VERSION = parseInt(process.versions.node, 10); -export const VALID_ENGINES = { node: [16, 18] }; +export const VALID_ENGINES = { node: [16, 18, 20] }; export const VALID_LOCALE_FORMATS = [/^ALL_[a-z]+$/, /^[a-z]+_ALL$/, /^[a-z]+(_[a-z]+)?$/]; From 5c03bf52468e0571627e6191f717a831d8f7fbf5 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 23 May 2023 20:58:55 +0000 Subject: [PATCH 027/320] 12.2.0 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 03bb6d3cdbc..f0ed8ac0c46 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.1.0", + "version": "12.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.1.0", + "version": "12.2.0", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index 7b1360d12de..7798ff03fb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.1.0", + "version": "12.2.0", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From acdf5e4a897441b8e36142d4bbe26abb407c881b Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 23 May 2023 20:59:08 +0000 Subject: [PATCH 028/320] [firebase-release] Removed change log and reset repo after 12.2.0 release --- CHANGELOG.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f19f1bfdec2..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +0,0 @@ -- Update error message when function deploy fails due to quota. (#5867) -- Fixes RTDB emulator 127.0.0.1 namespace resolution bug. (#5863) -- Improves RTDB emulator to GCF emulator network reliability. (#5863) -- Allow for Angular developers to both target a PWA and leverage `serveOptimizedImages`. (#5716) -- Multi-page applications that are fully staticly rendered are no longer treated as PWAs. (#5716) -- Add fast dev-mode support for devlopers using Nuxt v2. (#5716) -- Respect `ssr: false` and `baseURL` when using Nuxt. (#5716) -- Fix bug where JS SDK auto-init was not working for Vite while in dev-mode (#5610). -- Respect `FIREBASE_FRAMEWORKS_BUILD_TARGET` environment variable to override the default build target (#5572). -- Improves cleanup process when reloading emulated functions in debug mode. (#5878) -- Allow Web Frameworks to target NodeJS v20. (#5879) From ff2b2b24d210a783b32d35bc28da94d827127d08 Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Tue, 23 May 2023 19:00:07 -0400 Subject: [PATCH 029/320] gracefully close rules runtime (#4902) --- CHANGELOG.md | 1 + .../internal/tests.ts | 168 ------------------ .../multiple-targets/.firebaserc | 16 ++ .../rules/manager.test.ts | 41 +++-- scripts/storage-emulator-integration/run.sh | 2 - src/emulator/storage/index.ts | 8 +- src/emulator/storage/rules/manager.ts | 4 + src/emulator/storage/rules/runtime.ts | 26 ++- src/emulator/storage/server.ts | 101 +---------- 9 files changed, 65 insertions(+), 302 deletions(-) delete mode 100644 scripts/storage-emulator-integration/internal/tests.ts create mode 100644 scripts/storage-emulator-integration/multiple-targets/.firebaserc diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..c58039db6f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Gracefully close rules runtime on storage emulator stop (#4902) diff --git a/scripts/storage-emulator-integration/internal/tests.ts b/scripts/storage-emulator-integration/internal/tests.ts deleted file mode 100644 index fdf93440650..00000000000 --- a/scripts/storage-emulator-integration/internal/tests.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { expect } from "chai"; -import * as supertest from "supertest"; -import { StorageRulesFiles } from "../../../src/test/emulators/fixtures"; -import { TriggerEndToEndTest } from "../../integration-helpers/framework"; -import { - EMULATORS_SHUTDOWN_DELAY_MS, - getStorageEmulatorHost, - readEmulatorConfig, - TEST_SETUP_TIMEOUT, -} from "../utils"; - -const FIREBASE_PROJECT = process.env.FBTOOLS_TARGET_PROJECT || "fake-project-id"; -const EMULATOR_CONFIG = readEmulatorConfig(); -const STORAGE_EMULATOR_HOST = getStorageEmulatorHost(EMULATOR_CONFIG); - -describe("Storage emulator internal endpoints", () => { - let test: TriggerEndToEndTest; - - before(async function (this) { - this.timeout(TEST_SETUP_TIMEOUT); - process.env.STORAGE_EMULATOR_HOST = STORAGE_EMULATOR_HOST; - test = new TriggerEndToEndTest(FIREBASE_PROJECT, __dirname, EMULATOR_CONFIG); - await test.startEmulators(["--only", "auth,storage"]); - }); - - beforeEach(async () => { - // Reset emulator to default rules. - await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [StorageRulesFiles.readWriteIfAuth], - }, - }) - .expect(200); - }); - - after(async function (this) { - this.timeout(EMULATORS_SHUTDOWN_DELAY_MS); - delete process.env.STORAGE_EMULATOR_HOST; - await test.stopEmulators(); - }); - - describe("setRules", () => { - it("should set single ruleset", async () => { - await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [StorageRulesFiles.readWriteIfTrue], - }, - }) - .expect(200); - }); - - it("should set multiple rules/resource objects", async () => { - await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [ - { resource: "bucket_0", ...StorageRulesFiles.readWriteIfTrue }, - { resource: "bucket_1", ...StorageRulesFiles.readWriteIfAuth }, - ], - }, - }) - .expect(200); - }); - - it("should overwrite single ruleset with multiple rules/resource objects", async () => { - await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [StorageRulesFiles.readWriteIfTrue], - }, - }) - .expect(200); - - await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [ - { resource: "bucket_0", ...StorageRulesFiles.readWriteIfTrue }, - { resource: "bucket_1", ...StorageRulesFiles.readWriteIfAuth }, - ], - }, - }) - .expect(200); - }); - - it("should return 400 if rules.files array is missing", async () => { - const errorMessage = await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ rules: {} }) - .expect(400) - .then((res) => res.body.message); - - expect(errorMessage).to.equal("Request body must include 'rules.files' array"); - }); - - it("should return 400 if rules.files array has missing name field", async () => { - const errorMessage = await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [{ content: StorageRulesFiles.readWriteIfTrue.content }], - }, - }) - .expect(400) - .then((res) => res.body.message); - - expect(errorMessage).to.equal( - "Each member of 'rules.files' array must contain 'name' and 'content'" - ); - }); - - it("should return 400 if rules.files array has missing content field", async () => { - const errorMessage = await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [{ name: StorageRulesFiles.readWriteIfTrue.name }], - }, - }) - .expect(400) - .then((res) => res.body.message); - - expect(errorMessage).to.equal( - "Each member of 'rules.files' array must contain 'name' and 'content'" - ); - }); - - it("should return 400 if rules.files array has missing resource field", async () => { - const errorMessage = await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [ - { resource: "bucket_0", ...StorageRulesFiles.readWriteIfTrue }, - StorageRulesFiles.readWriteIfAuth, - ], - }, - }) - .expect(400) - .then((res) => res.body.message); - - expect(errorMessage).to.equal( - "Each member of 'rules.files' array must contain 'name', 'content', and 'resource'" - ); - }); - - it("should return 400 if rules.files array has invalid content", async () => { - const errorMessage = await supertest(STORAGE_EMULATOR_HOST) - .put("/internal/setRules") - .send({ - rules: { - files: [{ name: StorageRulesFiles.readWriteIfTrue.name, content: "foo" }], - }, - }) - .expect(400) - .then((res) => res.body.message); - - expect(errorMessage).to.equal("There was an error updating rules, see logs for more details"); - }); - }); -}); diff --git a/scripts/storage-emulator-integration/multiple-targets/.firebaserc b/scripts/storage-emulator-integration/multiple-targets/.firebaserc new file mode 100644 index 00000000000..caa6e980def --- /dev/null +++ b/scripts/storage-emulator-integration/multiple-targets/.firebaserc @@ -0,0 +1,16 @@ +{ + "projects": {}, + "targets": { + "fake-project-id": { + "storage": { + "allowNone": [ + "fake-project-id.appspot.com" + ], + "allowAll": [ + "fake-project-id-2.appspot.com" + ] + } + } + }, + "etags": {} +} diff --git a/scripts/storage-emulator-integration/rules/manager.test.ts b/scripts/storage-emulator-integration/rules/manager.test.ts index ff7c21cbd6a..d483cf1ec61 100644 --- a/scripts/storage-emulator-integration/rules/manager.test.ts +++ b/scripts/storage-emulator-integration/rules/manager.test.ts @@ -1,10 +1,6 @@ import { expect } from "chai"; -import { - createTmpDir, - StorageRulesFiles, - TIMEOUT_LONG, -} from "../../../src/test/emulators/fixtures"; +import { createTmpDir, StorageRulesFiles } from "../../../src/test/emulators/fixtures"; import { createStorageRulesManager, StorageRulesManager, @@ -16,27 +12,28 @@ import { isPermitted } from "../../../src/emulator/storage/rules/utils"; import { readFile } from "../../../src/fsutils"; import * as path from "path"; -const EMULATOR_LOAD_RULESET_DELAY_MS = 2000; +const EMULATOR_LOAD_RULESET_DELAY_MS = 20000; +const SETUP_TIMEOUT = 60000; -describe("Storage Rules Manager", function () { - const rulesRuntime = new StorageRulesRuntime(); +describe("Storage Rules Manager", () => { + let rulesRuntime: StorageRulesRuntime; const opts = { method: RulesetOperationMethod.GET, file: {}, path: "/b/bucket_0/o/" }; const projectId = "demo-project-id"; let rulesManager: StorageRulesManager; - // eslint-disable-next-line @typescript-eslint/no-invalid-this - this.timeout(TIMEOUT_LONG); - - beforeEach(async () => { + beforeEach(async function (this) { + this.timeout(SETUP_TIMEOUT); + rulesRuntime = new StorageRulesRuntime(); await rulesRuntime.start(); }); - afterEach(async () => { - rulesRuntime.stop(); + afterEach(async function (this) { + this.timeout(SETUP_TIMEOUT); await rulesManager.stop(); }); - it("should load multiple rulesets on start", async () => { + it("should load multiple rulesets on start", async function (this) { + this.timeout(SETUP_TIMEOUT); const rules = [ { resource: "bucket_0", rules: StorageRulesFiles.readWriteIfTrue }, { resource: "bucket_1", rules: StorageRulesFiles.readWriteIfAuth }, @@ -55,15 +52,23 @@ describe("Storage Rules Manager", function () { ).to.be.false; }); - it("should load single ruleset on start", async () => { - rulesManager = createStorageRulesManager(StorageRulesFiles.readWriteIfTrue, rulesRuntime); + it("should load single ruleset on start", async function (this) { + this.timeout(SETUP_TIMEOUT); + // Write rules to file + const fileName = "storage.rules"; + const testDir = createTmpDir("storage-files"); + appendBytes(testDir, fileName, Buffer.from(StorageRulesFiles.readWriteIfTrue.content)); + + const sourceFile = getSourceFile(testDir, fileName); + rulesManager = createStorageRulesManager(sourceFile, rulesRuntime); await rulesManager.start(); const ruleset = rulesManager.getRuleset("bucket"); expect(await isPermitted({ ...opts, ruleset: ruleset!, projectId })).to.be.true; }); - it("should reload ruleset on changes to source file", async () => { + it("should reload ruleset on changes to source file", async function (this) { + this.timeout(SETUP_TIMEOUT); // Write rules to file const fileName = "storage.rules"; const testDir = createTmpDir("storage-files"); diff --git a/scripts/storage-emulator-integration/run.sh b/scripts/storage-emulator-integration/run.sh index 5868973e74e..48f3a21a77c 100755 --- a/scripts/storage-emulator-integration/run.sh +++ b/scripts/storage-emulator-integration/run.sh @@ -14,8 +14,6 @@ mocha scripts/storage-emulator-integration/rules/*.test.ts mocha scripts/storage-emulator-integration/import/tests.ts -mocha scripts/storage-emulator-integration/internal/tests.ts - mocha scripts/storage-emulator-integration/multiple-targets/tests.ts mocha scripts/storage-emulator-integration/conformance/*.test.ts diff --git a/src/emulator/storage/index.ts b/src/emulator/storage/index.ts index 8979967759d..cadb34c61a0 100644 --- a/src/emulator/storage/index.ts +++ b/src/emulator/storage/index.ts @@ -6,7 +6,7 @@ import { createApp } from "./server"; import { StorageLayer, StoredFile } from "./files"; import { EmulatorLogger } from "../emulatorLogger"; import { createStorageRulesManager, StorageRulesManager } from "./rules/manager"; -import { StorageRulesIssues, StorageRulesRuntime } from "./rules/runtime"; +import { StorageRulesRuntime } from "./rules/runtime"; import { SourceFile } from "./rules/types"; import * as express from "express"; import { @@ -141,12 +141,6 @@ export class StorageEmulator implements EmulatorInstance { return this._app!; } - async replaceRules(rules: SourceFile | RulesConfig[]): Promise { - await this._rulesManager.stop(); - this._rulesManager = this.createRulesManager(rules); - return this._rulesManager.start(); - } - private createRulesManager(rules: SourceFile | RulesConfig[]): StorageRulesManager { return createStorageRulesManager(rules, this._rulesRuntime); } diff --git a/src/emulator/storage/rules/manager.ts b/src/emulator/storage/rules/manager.ts index 53d292196f9..9c4d8cd8526 100644 --- a/src/emulator/storage/rules/manager.ts +++ b/src/emulator/storage/rules/manager.ts @@ -60,6 +60,7 @@ class DefaultStorageRulesManager implements StorageRulesManager { } async start(): Promise { + this._runtime.start(); const issues = await this.loadRuleset(); this.updateWatcher(this._rules.name); return issues; @@ -71,6 +72,9 @@ class DefaultStorageRulesManager implements StorageRulesManager { async stop(): Promise { await this._watcher.close(); + if (this._runtime.alive) { + await this._runtime.stop(); + } } private updateWatcher(rulesFile: string): void { diff --git a/src/emulator/storage/rules/runtime.ts b/src/emulator/storage/rules/runtime.ts index 127cddd8890..ceb062e91c3 100644 --- a/src/emulator/storage/rules/runtime.ts +++ b/src/emulator/storage/rules/runtime.ts @@ -118,6 +118,9 @@ export class StorageRulesRuntime { } async start(autoDownload = true) { + if (this.alive) { + return; + } const downloadDetails = DownloadDetails[Emulators.STORAGE]; const hasEmulator = fs.existsSync(downloadDetails.downloadPath); @@ -144,11 +147,10 @@ export class StorageRulesRuntime { stdio: ["pipe", "pipe", "pipe"], }); - this._childprocess.on("exit", (code) => { + this._childprocess.on("exit", () => { this._alive = false; - if (code !== 130 /* SIGINT */) { - throw new FirebaseError("Storage Emulator Rules runtime exited unexpectedly."); - } + this._childprocess?.removeAllListeners(); + this._childprocess = undefined; }); const startPromise = new Promise((resolve) => { @@ -221,14 +223,24 @@ export class StorageRulesRuntime { return startPromise; } - stop() { - this._childprocess?.kill("SIGINT"); + stop(): Promise { + EmulatorLogger.forEmulator(Emulators.STORAGE).log("DEBUG", "Stopping rules runtime."); + return new Promise((resolve) => { + if (this.alive) { + this._childprocess!.on("exit", () => { + resolve(); + }); + this._childprocess?.kill("SIGINT"); + } else { + resolve(); + } + }); } private async _sendRequest(rab: RuntimeActionBundle, overrideId?: number) { if (!this._childprocess) { throw new FirebaseError( - "Attempted to send Cloud Storage rules request before child was ready" + "Failed to send Cloud Storage rules request due to rules runtime not available." ); } diff --git a/src/emulator/storage/server.ts b/src/emulator/storage/server.ts index 1489f5fb09f..d5e82e53ac4 100644 --- a/src/emulator/storage/server.ts +++ b/src/emulator/storage/server.ts @@ -4,10 +4,8 @@ import { EmulatorLogger } from "../emulatorLogger"; import { Emulators } from "../types"; import * as bodyParser from "body-parser"; import { createCloudEndpoints } from "./apis/gcloud"; -import { RulesConfig, StorageEmulator } from "./index"; +import { StorageEmulator } from "./index"; import { createFirebaseEndpoints } from "./apis/firebase"; -import { InvalidArgumentError } from "../auth/errors"; -import { SourceFile } from "./rules/types"; /** * @param defaultProjectId @@ -79,91 +77,6 @@ export function createApp( res.sendStatus(200); }); - /** - * Internal endpoint to overwrite current rules. Callers provide either a single set of rules to - * be applied to all resources or an array of rules/resource objects. - * - * Example payload for single set of rules: - * - * ``` - * { - * rules: { - * files: [{ name: , content: }] - * } - * } - * ``` - * - * Example payload for multiple rules/resource objects: - * - * ``` - * { - * rules: { - * files: [ - * { name: , content: , resource: }, - * ... - * ] - * } - * } - * ``` - */ - app.put("/internal/setRules", async (req, res) => { - const rulesRaw = req.body.rules; - if (!(rulesRaw && Array.isArray(rulesRaw.files) && rulesRaw.files.length > 0)) { - res.status(400).json({ - message: "Request body must include 'rules.files' array", - }); - return; - } - - const { files } = rulesRaw; - - function parseRulesFromFiles(files: Array): SourceFile | RulesConfig[] { - if (files.length === 1) { - const file = files[0]; - if (!isRulesFile(file)) { - throw new InvalidArgumentError( - "Each member of 'rules.files' array must contain 'name' and 'content'" - ); - } - return { name: file.name, content: file.content }; - } - - const rules: RulesConfig[] = []; - for (const file of files) { - if (!isRulesFile(file) || !file.resource) { - throw new InvalidArgumentError( - "Each member of 'rules.files' array must contain 'name', 'content', and 'resource'" - ); - } - rules.push({ resource: file.resource, rules: { name: file.name, content: file.content } }); - } - return rules; - } - - let rules: SourceFile | RulesConfig[]; - try { - rules = parseRulesFromFiles(files); - } catch (err) { - if (err instanceof InvalidArgumentError) { - res.status(400).json({ message: err.message }); - return; - } - throw err; - } - - const issues = await emulator.replaceRules(rules); - if (issues.errors.length > 0) { - res.status(400).json({ - message: "There was an error updating rules, see logs for more details", - }); - return; - } - - res.status(200).json({ - message: "Rules updated successfully", - }); - }); - app.post("/internal/reset", (req, res) => { emulator.reset(); res.sendStatus(200); @@ -174,15 +87,3 @@ export function createApp( return Promise.resolve(app); } - -interface RulesFile { - name: string; - content: string; - resource?: string; -} - -function isRulesFile(file: unknown): file is RulesFile { - return ( - typeof (file as RulesFile).name === "string" && typeof (file as RulesFile).content === "string" - ); -} From 68c71b13b95367d88d5bf610c4fe9ad1356c5a4c Mon Sep 17 00:00:00 2001 From: James Daniels Date: Wed, 24 May 2023 15:30:11 -0400 Subject: [PATCH 030/320] Always assume build target of production on deploy (#5892) --- CHANGELOG.md | 1 + src/frameworks/utils.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c58039db6f8..30c7d20f578 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Gracefully close rules runtime on storage emulator stop (#4902) +- Always assume build target of production when deploying a web framework, unless overridden (#5892) diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index 374297688a5..5ac49c2027c 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -290,6 +290,8 @@ export function getFrameworksBuildTarget(purpose: BUILD_TARGET_PURPOSE, validOpt ); } return frameworksBuild; + } else if (purpose === "deploy") { + return "production"; // TODO handle other language / frameworks environment variables } else if (process.env.NODE_ENV) { switch (process.env.NODE_ENV) { @@ -305,7 +307,7 @@ export function getFrameworksBuildTarget(purpose: BUILD_TARGET_PURPOSE, validOpt )}` ); } - } else if (purpose !== "serve") { + } else if (purpose === "test") { return "production"; } else { return "development"; From 14b07556e8f360d1d0235563c1f967002aa6782b Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 24 May 2023 13:45:29 -0700 Subject: [PATCH 031/320] Update default Storage rules to contain example cross-srevice-rules (#5298) --- templates/init/storage/storage.rules | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/init/storage/storage.rules b/templates/init/storage/storage.rules index 9f33d22cbd7..f08744f032e 100644 --- a/templates/init/storage/storage.rules +++ b/templates/init/storage/storage.rules @@ -1,4 +1,8 @@ rules_version = '2'; + +// Craft rules based on data in your Firestore database +// allow write: if firestore.get( +// /databases/(default)/documents/users/$(request.auth.uid)).data.isAdmin; service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { From ea969947792152e781e4011ba38e380739f9f068 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Wed, 24 May 2023 21:38:25 +0000 Subject: [PATCH 032/320] 12.2.1 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index f0ed8ac0c46..860dec4d957 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.2.0", + "version": "12.2.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.2.0", + "version": "12.2.1", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index 7798ff03fb6..2279debc505 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.2.0", + "version": "12.2.1", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From e57b49abb9417278cd49c8a1b1c909c2d5345463 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Wed, 24 May 2023 21:38:38 +0000 Subject: [PATCH 033/320] [firebase-release] Removed change log and reset repo after 12.2.1 release --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30c7d20f578..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +0,0 @@ -- Gracefully close rules runtime on storage emulator stop (#4902) -- Always assume build target of production when deploying a web framework, unless overridden (#5892) From 51d2fd574a2c5e81bf51acb0b89409182edb40e9 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 25 May 2023 17:07:43 -0400 Subject: [PATCH 034/320] Follow on fixes for #5892 (#5895) * Don't allow the devModeHandle if purpose is deploy * `context._name` is gone?! Manually pass "purpose" rather than leaning poorly typed options * Get more defensive w/types * Rename purpose of "serve" to "emulate" * Drop the Node 16 check, since v12 is 16+ * Purpose of "test" should default to production target * Reject the devModeHost if process exits * Replace old broken e2e test with the new frameworks test Fixes #5896 --- .github/workflows/node-test.yml | 1 - CHANGELOG.md | 1 + package.json | 5 +- scripts/frameworks-tests/run.sh | 32 - .../frameworks-tests/vite-project/.gitignore | 24 - .../frameworks-tests/vite-project/counter.js | 9 - .../vite-project/firebase.json | 15 - .../frameworks-tests/vite-project/index.html | 13 - .../vite-project/javascript.svg | 1 - scripts/frameworks-tests/vite-project/main.js | 23 - .../vite-project/package-lock.json | 881 ------------------ .../vite-project/package.json | 14 - .../vite-project/public/vite.svg | 1 - .../frameworks-tests/vite-project/style.css | 97 -- src/deploy/index.ts | 2 +- src/emulator/commandUtils.ts | 2 +- src/emulator/controller.ts | 11 +- src/frameworks/angular/index.ts | 5 +- src/frameworks/astro/index.ts | 3 +- src/frameworks/index.ts | 47 +- src/frameworks/interfaces.ts | 19 +- src/frameworks/nuxt/index.ts | 4 +- src/frameworks/nuxt2/index.ts | 4 +- src/frameworks/utils.ts | 36 +- src/frameworks/vite/index.ts | 4 +- src/serve/index.ts | 2 +- 26 files changed, 83 insertions(+), 1173 deletions(-) delete mode 100755 scripts/frameworks-tests/run.sh delete mode 100644 scripts/frameworks-tests/vite-project/.gitignore delete mode 100644 scripts/frameworks-tests/vite-project/counter.js delete mode 100644 scripts/frameworks-tests/vite-project/firebase.json delete mode 100644 scripts/frameworks-tests/vite-project/index.html delete mode 100644 scripts/frameworks-tests/vite-project/javascript.svg delete mode 100644 scripts/frameworks-tests/vite-project/main.js delete mode 100644 scripts/frameworks-tests/vite-project/package-lock.json delete mode 100644 scripts/frameworks-tests/vite-project/package.json delete mode 100644 scripts/frameworks-tests/vite-project/public/vite.svg delete mode 100644 scripts/frameworks-tests/vite-project/style.css diff --git a/.github/workflows/node-test.yml b/.github/workflows/node-test.yml index d4f98b11b3d..5a089572232 100644 --- a/.github/workflows/node-test.yml +++ b/.github/workflows/node-test.yml @@ -93,7 +93,6 @@ jobs: - npm run test:storage-emulator-integration - npm run test:triggers-end-to-end - npm run test:triggers-end-to-end:inspect - - npm run test:webframeworks-deploy steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..8f658a1f206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Address additional cases where we were attempting to deploy a framework's development bundle (#5895) diff --git a/package.json b/package.json index 2279debc505..79b3482916a 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "test:emulator": "bash ./scripts/emulator-tests/run.sh", "test:extensions-deploy": "bash ./scripts/extensions-deploy-tests/run.sh", "test:extensions-emulator": "bash ./scripts/extensions-emulator-tests/run.sh", - "test:frameworks": "bash ./scripts/frameworks-tests/run.sh", + "test:frameworks": "bash ./scripts/webframeworks-deploy-tests/run.sh", "test:functions-deploy": "bash ./scripts/functions-deploy-tests/run.sh", "test:functions-discover": "bash ./scripts/functions-discover-tests/run.sh", "test:hosting": "bash ./scripts/hosting-tests/run.sh", @@ -39,8 +39,7 @@ "test:triggers-end-to-end": "bash ./scripts/triggers-end-to-end-tests/run.sh", "test:triggers-end-to-end:inspect": "bash ./scripts/triggers-end-to-end-tests/run.sh inspect", "test:storage-deploy": "bash ./scripts/storage-deploy-tests/run.sh", - "test:storage-emulator-integration": "bash ./scripts/storage-emulator-integration/run.sh", - "test:webframeworks-deploy": "bash ./scripts/webframeworks-deploy-tests/run.sh" + "test:storage-emulator-integration": "bash ./scripts/storage-emulator-integration/run.sh" }, "files": [ "lib", diff --git a/scripts/frameworks-tests/run.sh b/scripts/frameworks-tests/run.sh deleted file mode 100755 index be97ecbc507..00000000000 --- a/scripts/frameworks-tests/run.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -set -e -CWD="$(pwd)" - -echo "Running in ${CWD}" -echo "Running with node: $(which node)" -echo "Running with npm: $(which npm)" -echo "Running with Application Creds: ${GOOGLE_APPLICATION_CREDENTIALS}" - -echo "Target project: ${FBTOOLS_TARGET_PROJECT}" - -echo "Installing firebase-tools..." -./scripts/clean-install.sh -echo "Installed firebase-tools: $(which firebase)" - -echo "Enabling experiment..." -firebase experiments:enable webframeworks -echo "Enabled experiment." - -echo "Vite..." -cd scripts/frameworks-tests/vite-project -npm ci - -echo "Testing local emulators:start..." -firebase emulators:start --project "${FBTOOLS_TARGET_PROJECT}" & -PID="$!" -sleep 15 -VALUE="$(curl localhost:8534)" -echo "${VALUE}" | grep "Vite App" || (echo "Expected response to include \"Vite App\"." && false) -kill "$PID" -wait -echo "Tested local serve." diff --git a/scripts/frameworks-tests/vite-project/.gitignore b/scripts/frameworks-tests/vite-project/.gitignore deleted file mode 100644 index a547bf36d8d..00000000000 --- a/scripts/frameworks-tests/vite-project/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/scripts/frameworks-tests/vite-project/counter.js b/scripts/frameworks-tests/vite-project/counter.js deleted file mode 100644 index 12ae65abfae..00000000000 --- a/scripts/frameworks-tests/vite-project/counter.js +++ /dev/null @@ -1,9 +0,0 @@ -export function setupCounter(element) { - let counter = 0 - const setCounter = (count) => { - counter = count - element.innerHTML = `count is ${counter}` - } - element.addEventListener('click', () => setCounter(++counter)) - setCounter(0) -} diff --git a/scripts/frameworks-tests/vite-project/firebase.json b/scripts/frameworks-tests/vite-project/firebase.json deleted file mode 100644 index 5b87e488e17..00000000000 --- a/scripts/frameworks-tests/vite-project/firebase.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "hosting": { - "source": ".", - "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" - ] - }, - "emulators": { - "hosting": { - "port": "8534" - } - } -} diff --git a/scripts/frameworks-tests/vite-project/index.html b/scripts/frameworks-tests/vite-project/index.html deleted file mode 100644 index 2ad7b1ab9e6..00000000000 --- a/scripts/frameworks-tests/vite-project/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite App - - -
- - - diff --git a/scripts/frameworks-tests/vite-project/javascript.svg b/scripts/frameworks-tests/vite-project/javascript.svg deleted file mode 100644 index f9abb2b728d..00000000000 --- a/scripts/frameworks-tests/vite-project/javascript.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/scripts/frameworks-tests/vite-project/main.js b/scripts/frameworks-tests/vite-project/main.js deleted file mode 100644 index 727b4ea209e..00000000000 --- a/scripts/frameworks-tests/vite-project/main.js +++ /dev/null @@ -1,23 +0,0 @@ -import './style.css' -import javascriptLogo from './javascript.svg' -import { setupCounter } from './counter.js' - -document.querySelector('#app').innerHTML = ` -
- - - - - - -

Hello Vite!

-
- -
-

- Click on the Vite logo to learn more -

-
-` - -setupCounter(document.querySelector('#counter')) diff --git a/scripts/frameworks-tests/vite-project/package-lock.json b/scripts/frameworks-tests/vite-project/package-lock.json deleted file mode 100644 index a33faf3c34c..00000000000 --- a/scripts/frameworks-tests/vite-project/package-lock.json +++ /dev/null @@ -1,881 +0,0 @@ -{ - "name": "vite-project", - "version": "0.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "vite-project", - "version": "0.0.0", - "devDependencies": { - "vite": "^3.1.0" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz", - "integrity": "sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz", - "integrity": "sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.10.tgz", - "integrity": "sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.10", - "@esbuild/linux-loong64": "0.15.10", - "esbuild-android-64": "0.15.10", - "esbuild-android-arm64": "0.15.10", - "esbuild-darwin-64": "0.15.10", - "esbuild-darwin-arm64": "0.15.10", - "esbuild-freebsd-64": "0.15.10", - "esbuild-freebsd-arm64": "0.15.10", - "esbuild-linux-32": "0.15.10", - "esbuild-linux-64": "0.15.10", - "esbuild-linux-arm": "0.15.10", - "esbuild-linux-arm64": "0.15.10", - "esbuild-linux-mips64le": "0.15.10", - "esbuild-linux-ppc64le": "0.15.10", - "esbuild-linux-riscv64": "0.15.10", - "esbuild-linux-s390x": "0.15.10", - "esbuild-netbsd-64": "0.15.10", - "esbuild-openbsd-64": "0.15.10", - "esbuild-sunos-64": "0.15.10", - "esbuild-windows-32": "0.15.10", - "esbuild-windows-64": "0.15.10", - "esbuild-windows-arm64": "0.15.10" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz", - "integrity": "sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz", - "integrity": "sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz", - "integrity": "sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz", - "integrity": "sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz", - "integrity": "sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz", - "integrity": "sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz", - "integrity": "sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz", - "integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz", - "integrity": "sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz", - "integrity": "sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz", - "integrity": "sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz", - "integrity": "sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz", - "integrity": "sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz", - "integrity": "sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz", - "integrity": "sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz", - "integrity": "sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz", - "integrity": "sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz", - "integrity": "sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz", - "integrity": "sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz", - "integrity": "sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "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": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", - "dev": true, - "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.16", - "resolve": "^1.22.1", - "rollup": "~2.78.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "less": "*", - "sass": "*", - "stylus": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "terser": { - "optional": true - } - } - } - }, - "dependencies": { - "@esbuild/android-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz", - "integrity": "sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz", - "integrity": "sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==", - "dev": true, - "optional": true - }, - "esbuild": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.10.tgz", - "integrity": "sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.15.10", - "@esbuild/linux-loong64": "0.15.10", - "esbuild-android-64": "0.15.10", - "esbuild-android-arm64": "0.15.10", - "esbuild-darwin-64": "0.15.10", - "esbuild-darwin-arm64": "0.15.10", - "esbuild-freebsd-64": "0.15.10", - "esbuild-freebsd-arm64": "0.15.10", - "esbuild-linux-32": "0.15.10", - "esbuild-linux-64": "0.15.10", - "esbuild-linux-arm": "0.15.10", - "esbuild-linux-arm64": "0.15.10", - "esbuild-linux-mips64le": "0.15.10", - "esbuild-linux-ppc64le": "0.15.10", - "esbuild-linux-riscv64": "0.15.10", - "esbuild-linux-s390x": "0.15.10", - "esbuild-netbsd-64": "0.15.10", - "esbuild-openbsd-64": "0.15.10", - "esbuild-sunos-64": "0.15.10", - "esbuild-windows-32": "0.15.10", - "esbuild-windows-64": "0.15.10", - "esbuild-windows-arm64": "0.15.10" - } - }, - "esbuild-android-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz", - "integrity": "sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz", - "integrity": "sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz", - "integrity": "sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz", - "integrity": "sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz", - "integrity": "sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz", - "integrity": "sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz", - "integrity": "sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz", - "integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz", - "integrity": "sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz", - "integrity": "sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz", - "integrity": "sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz", - "integrity": "sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz", - "integrity": "sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz", - "integrity": "sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz", - "integrity": "sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz", - "integrity": "sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz", - "integrity": "sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz", - "integrity": "sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz", - "integrity": "sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.15.10", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz", - "integrity": "sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==", - "dev": true, - "optional": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", - "dev": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", - "dev": true, - "requires": { - "esbuild": "^0.15.9", - "fsevents": "~2.3.2", - "postcss": "^8.4.16", - "resolve": "^1.22.1", - "rollup": "~2.78.0" - } - } - } -} diff --git a/scripts/frameworks-tests/vite-project/package.json b/scripts/frameworks-tests/vite-project/package.json deleted file mode 100644 index 4e55fa3ed80..00000000000 --- a/scripts/frameworks-tests/vite-project/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "vite-project", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^3.1.0" - } -} \ No newline at end of file diff --git a/scripts/frameworks-tests/vite-project/public/vite.svg b/scripts/frameworks-tests/vite-project/public/vite.svg deleted file mode 100644 index e7b8dfb1b2a..00000000000 --- a/scripts/frameworks-tests/vite-project/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/scripts/frameworks-tests/vite-project/style.css b/scripts/frameworks-tests/vite-project/style.css deleted file mode 100644 index 12320801d36..00000000000 --- a/scripts/frameworks-tests/vite-project/style.css +++ /dev/null @@ -1,97 +0,0 @@ -:root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -#app { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.vanilla:hover { - filter: drop-shadow(0 0 2em #f7df1eaa); -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 64013e4603f..54a64b571cb 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -66,7 +66,7 @@ export const deploy = async function ( const config = options.config.get("hosting"); if (Array.isArray(config) ? config.some((it) => it.source) : config.source) { experiments.assertEnabled("webframeworks", "deploy a web framework from source"); - await prepareFrameworks(targetNames, context, options); + await prepareFrameworks("deploy", targetNames, context, options); } } diff --git a/src/emulator/commandUtils.ts b/src/emulator/commandUtils.ts index b1c8ea4a4a7..712288d7e2a 100644 --- a/src/emulator/commandUtils.ts +++ b/src/emulator/commandUtils.ts @@ -434,7 +434,7 @@ export async function emulatorExec(script: string, options: any): Promise let deprecationNotices; try { const showUI = !!options.ui; - ({ deprecationNotices } = await controller.startAll(options, showUI)); + ({ deprecationNotices } = await controller.startAll(options, showUI, true)); exitCode = await runScript(script, extraEnv); await controller.onExit(options); } finally { diff --git a/src/emulator/controller.ts b/src/emulator/controller.ts index a245b29eab9..089250f00c7 100644 --- a/src/emulator/controller.ts +++ b/src/emulator/controller.ts @@ -250,7 +250,8 @@ interface EmulatorOptions extends Options { */ export async function startAll( options: EmulatorOptions, - showUI = true + showUI = true, + runningTestScript = false ): Promise<{ deprecationNotices: string[] }> { // Emulators config is specified in firebase.json as: // "emulators": { @@ -463,7 +464,13 @@ export async function startAll( } } // This may add additional sources for Functions emulator and must be done before it. - await prepareFrameworks(targets, options, options, emulators); + await prepareFrameworks( + runningTestScript ? "test" : "emulate", + targets, + undefined, + options, + emulators + ); } const projectDir = (options.extDevDir || options.config.projectDir) as string; diff --git a/src/frameworks/angular/index.ts b/src/frameworks/angular/index.ts index 26faa0afd72..5c4dd4bdeec 100644 --- a/src/frameworks/angular/index.ts +++ b/src/frameworks/angular/index.ts @@ -98,7 +98,7 @@ export async function getDevModeHandle(dir: string, configuration: string) { const { targetStringFromTarget } = relativeRequire(dir, "@angular-devkit/architect"); const { serveTarget } = await getContext(dir, configuration); if (!serveTarget) throw new Error("Could not find the serveTarget"); - const host = new Promise((resolve) => { + const host = new Promise((resolve, reject) => { // Can't use scheduleTarget since that—like prerender—is failing on an ESM bug // will just grep for the hostname const cli = getNodeModuleBin("ng", dir); @@ -113,6 +113,7 @@ export async function getDevModeHandle(dir: string, configuration: string) { serve.stderr.on("data", (data: any) => { process.stderr.write(data); }); + serve.on("exit", reject); }); return simpleProxy(await host); } @@ -146,7 +147,7 @@ export async function getValidBuildTargets(purpose: BUILD_TARGET_PURPOSE, dir: s const validTargetNames = new Set(["development", "production"]); try { const { workspaceProject, browserTarget, serverTarget, serveTarget } = await getContext(dir); - const { target } = ((purpose === "serve" && serveTarget) || serverTarget || browserTarget)!; + const { target } = ((purpose === "emulate" && serveTarget) || serverTarget || browserTarget)!; const workspaceTarget = workspaceProject.targets.get(target)!; Object.keys(workspaceTarget.configurations || {}).forEach((it) => validTargetNames.add(it)); } catch (e) { diff --git a/src/frameworks/astro/index.ts b/src/frameworks/astro/index.ts index 76481ca61d0..b7d7d804d39 100644 --- a/src/frameworks/astro/index.ts +++ b/src/frameworks/astro/index.ts @@ -64,7 +64,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: st } export async function getDevModeHandle(cwd: string) { - const host = new Promise((resolve) => { + const host = new Promise((resolve, reject) => { const cli = getNodeModuleBin("astro", cwd); const serve = spawn(cli, ["dev"], { cwd }); serve.stdout.on("data", (data: any) => { @@ -75,6 +75,7 @@ export async function getDevModeHandle(cwd: string) { serve.stderr.on("data", (data: any) => { process.stderr.write(data); }); + serve.on("exit", reject); }); return simpleProxy(await host); } diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index 713bd48b5fe..21be5fa8c73 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -5,7 +5,6 @@ import { sync as spawnSync } from "cross-spawn"; import { copyFile, readdir, readFile, rm, writeFile } from "fs/promises"; import { mkdirp, pathExists, stat } from "fs-extra"; import * as process from "node:process"; -import * as semver from "semver"; import * as glob from "glob"; import { needProjectId } from "../projectUtils"; @@ -42,10 +41,18 @@ import { VALID_ENGINES, WebFrameworks, } from "./constants"; -import { BUILD_TARGET_PURPOSE, BuildResult, FirebaseDefaults, Framework } from "./interfaces"; +import { + BUILD_TARGET_PURPOSE, + BuildResult, + FirebaseDefaults, + Framework, + FrameworkContext, + FrameworksOptions, +} from "./interfaces"; import { logWarning } from "../utils"; import { ensureTargeted } from "../functions/ensureTargeted"; import { isDeepStrictEqual } from "util"; +import { resolveProjectPath } from "../projectPath"; export { WebFrameworks }; @@ -100,21 +107,14 @@ function memoizeBuild( * */ export async function prepareFrameworks( + purpose: BUILD_TARGET_PURPOSE, targetNames: string[], - context: any, - options: any, + context: FrameworkContext | undefined, + options: FrameworksOptions, emulators: EmulatorInfo[] = [] ): Promise { - // `firebase-frameworks` requires Node >= 16. We must check for this to avoid horrible errors. - const nodeVersion = process.version; - if (!semver.satisfies(nodeVersion, ">=16.0.0")) { - throw new FirebaseError( - `The frameworks awareness feature requires Node.JS >= 16 and npm >= 8 in order to work correctly, due to some of the downstream dependencies. Please upgrade your version of Node.JS, reinstall firebase-tools, and give it another go.` - ); - } - - const project = needProjectId(context); - const { projectRoot } = options; + const project = needProjectId(context || options); + const projectRoot = resolveProjectPath(options, "."); const account = getProjectDefaultAccount(projectRoot); // options.site is not present when emulated. We could call requireHostingSite but IAM permissions haven't // been booted up (at this point) and we may be offline, so just use projectId. Most of the time @@ -260,11 +260,11 @@ export async function prepareFrameworks( ); const hostingEmulatorInfo = emulators.find((e) => e.name === Emulators.HOSTING); - const buildTargetPurpose: BUILD_TARGET_PURPOSE = - context._name === "deploy" ? "deploy" : context._name === "emulators:exec" ? "test" : "serve"; - const validBuildTargets = await getValidBuildTargets(buildTargetPurpose, getProjectPath()); - const frameworksBuildTarget = getFrameworksBuildTarget(buildTargetPurpose, validBuildTargets); - const useDevModeHandle = await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath()); + const validBuildTargets = await getValidBuildTargets(purpose, getProjectPath()); + const frameworksBuildTarget = getFrameworksBuildTarget(purpose, validBuildTargets); + const useDevModeHandle = + purpose !== "deploy" && + (await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath())); let codegenFunctionsDirectory: Framework["ɵcodegenFunctionsDirectory"]; @@ -321,7 +321,7 @@ export async function prepareFrameworks( process.env.__FIREBASE_DEFAULTS__ = JSON.stringify(firebaseDefaults); } - if (context.hostingChannel) { + if (context?.hostingChannel) { experiments.assertEnabled( "pintags", "deploy an app that requires a backend to a preview channel" @@ -344,12 +344,7 @@ export async function prepareFrameworks( // This is just a fallback for previous behavior if the user manually // disables the pintags experiment (e.g. there is a break and they would // rather disable the experiment than roll back). - if ( - !experiments.isEnabled("pintags") || - context._name === "serve" || - context._name === "emulators:start" || - context._name === "emulators:exec" - ) { + if (!experiments.isEnabled("pintags") || purpose !== "deploy") { if (!targetNames.includes("functions")) { targetNames.unshift("functions"); } diff --git a/src/frameworks/interfaces.ts b/src/frameworks/interfaces.ts index c851726b1cd..d8f79a23d7c 100644 --- a/src/frameworks/interfaces.ts +++ b/src/frameworks/interfaces.ts @@ -1,6 +1,8 @@ import { IncomingMessage, ServerResponse } from "http"; import { EmulatorInfo } from "../emulator/types"; import { HostingHeaders, HostingRedirects, HostingRewrites } from "../firebaseConfig"; +import { HostingOptions } from "../hosting/options"; +import { Options } from "../options"; // These serve as the order of operations for discovery // E.g, a framework utilizing Vite should be given priority @@ -32,6 +34,19 @@ export interface BuildResult { i18n?: boolean; } +export type RequestHandler = (req: IncomingMessage, res: ServerResponse, next: () => void) => void; + +export type FrameworksOptions = HostingOptions & + Options & { + frameworksDevModeHandle?: RequestHandler; + nonInteractive?: boolean; + }; + +export type FrameworkContext = { + projectId?: string; + hostingChannel?: string; +}; + export interface Framework { discover: (dir: string) => Promise; type: FrameworkType; @@ -44,7 +59,7 @@ export interface Framework { dir: string, target: string, hostingEmulatorInfo?: EmulatorInfo - ) => Promise<(req: IncomingMessage, res: ServerResponse, next: () => void) => void>; + ) => Promise; ɵcodegenPublicDirectory: ( dir: string, dest: string, @@ -70,7 +85,7 @@ export interface Framework { shouldUseDevModeHandle?: (target: string, dir: string) => Promise; } -export type BUILD_TARGET_PURPOSE = "deploy" | "test" | "serve"; +export type BUILD_TARGET_PURPOSE = "deploy" | "test" | "emulate"; // TODO pull from @firebase/util when published export interface FirebaseDefaults { diff --git a/src/frameworks/nuxt/index.ts b/src/frameworks/nuxt/index.ts index fffd1164167..a5871f1fb52 100644 --- a/src/frameworks/nuxt/index.ts +++ b/src/frameworks/nuxt/index.ts @@ -90,7 +90,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string) { } export async function getDevModeHandle(cwd: string) { - const host = new Promise((resolve) => { + const host = new Promise((resolve, reject) => { const cli = getNodeModuleBin("nuxt", cwd); const serve = spawn(cli, ["dev"], { cwd: cwd }); @@ -104,6 +104,8 @@ export async function getDevModeHandle(cwd: string) { serve.stderr.on("data", (data: any) => { process.stderr.write(data); }); + + serve.on("exit", reject); }); return simpleProxy(await host); diff --git a/src/frameworks/nuxt2/index.ts b/src/frameworks/nuxt2/index.ts index 5609efc56d1..f31a99ba6d7 100644 --- a/src/frameworks/nuxt2/index.ts +++ b/src/frameworks/nuxt2/index.ts @@ -97,7 +97,7 @@ export async function ɵcodegenFunctionsDirectory(rootDir: string, destDir: stri } export async function getDevModeHandle(cwd: string) { - const host = new Promise((resolve) => { + const host = new Promise((resolve, reject) => { const cli = getNodeModuleBin("nuxt", cwd); const serve = spawn(cli, ["dev"], { cwd }); @@ -111,6 +111,8 @@ export async function getDevModeHandle(cwd: string) { serve.stderr.on("data", (data: any) => { process.stderr.write(data); }); + + serve.on("exit", reject); }); return simpleProxy(await host); diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index 5ac49c2027c..265c742adc5 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -290,26 +290,22 @@ export function getFrameworksBuildTarget(purpose: BUILD_TARGET_PURPOSE, validOpt ); } return frameworksBuild; - } else if (purpose === "deploy") { + } else if (["test", "deploy"].includes(purpose)) { return "production"; - // TODO handle other language / frameworks environment variables - } else if (process.env.NODE_ENV) { - switch (process.env.NODE_ENV) { - case "development": - return "development"; - case "production": - case "test": - return "production"; - default: - throw new FirebaseError( - `We cannot infer your build target from a non-standard NODE_ENV. Please set the FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable. Valid values are: ${validOptions.join( - ", " - )}` - ); - } - } else if (purpose === "test") { - return "production"; - } else { - return "development"; + } + // TODO handle other language / frameworks environment variables + switch (process.env.NODE_ENV) { + case undefined: + case "development": + return "development"; + case "production": + case "test": + return "production"; + default: + throw new FirebaseError( + `We cannot infer your build target from a non-standard NODE_ENV. Please set the FIREBASE_FRAMEWORKS_BUILD_TARGET environment variable. Valid values are: ${validOptions.join( + ", " + )}` + ); } } diff --git a/src/frameworks/vite/index.ts b/src/frameworks/vite/index.ts index 959145a867e..3a16558c069 100644 --- a/src/frameworks/vite/index.ts +++ b/src/frameworks/vite/index.ts @@ -84,7 +84,7 @@ export async function ɵcodegenPublicDirectory(root: string, dest: string) { } export async function getDevModeHandle(dir: string) { - const host = new Promise((resolve) => { + const host = new Promise((resolve, reject) => { // Can't use scheduleTarget since that—like prerender—is failing on an ESM bug // will just grep for the hostname const cli = getNodeModuleBin("vite", dir); @@ -97,6 +97,8 @@ export async function getDevModeHandle(dir: string) { serve.stderr.on("data", (data: any) => { process.stderr.write(data); }); + + serve.on("exit", reject); }); return simpleProxy(await host); } diff --git a/src/serve/index.ts b/src/serve/index.ts index 925447f10d3..59c34902b15 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -25,7 +25,7 @@ export async function serve(options: any): Promise { options.port = parseInt(options.port, 10); if (targetNames.includes("hosting") && config.extract(options).some((it: any) => it.source)) { experiments.assertEnabled("webframeworks", "emulate a web framework"); - await prepareFrameworks(targetNames, options, options); + await prepareFrameworks("emulate", targetNames, undefined, options); } const isDemoProject = Constants.isDemoProject(getProjectId(options) || ""); targetNames.forEach((targetName) => { From 4bc4304460a8430cfd5704c1a4f04266d191edd5 Mon Sep 17 00:00:00 2001 From: blidd-google <112491344+blidd-google@users.noreply.github.com> Date: Tue, 30 May 2023 14:14:18 -0400 Subject: [PATCH 035/320] change v2 scheduled fns to be handled as http by emulator (#5891) --- src/emulator/functionsEmulatorShared.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/emulator/functionsEmulatorShared.ts b/src/emulator/functionsEmulatorShared.ts index 9e474cb1489..87f6cbc1664 100644 --- a/src/emulator/functionsEmulatorShared.ts +++ b/src/emulator/functionsEmulatorShared.ts @@ -454,6 +454,9 @@ export function getSignatureType(def: EmulatedTriggerDefinition): SignatureType if (def.httpsTrigger || def.blockingTrigger) { return "http"; } + if (def.platform === "gcfv2" && def.schedule) { + return "http"; + } // TODO: As implemented, emulated CF3v1 functions cannot receive events in CloudEvent format, and emulated CF3v2 // functions cannot receive events in legacy format. This conflicts with our goal of introducing a 'compat' layer // that allows CF3v1 functions to target GCFv2 and vice versa. From ce5d7823b6cbac6d0fbe7e7f6fcaf421700c075a Mon Sep 17 00:00:00 2001 From: joehan Date: Tue, 30 May 2023 16:36:14 -0700 Subject: [PATCH 036/320] Update docs link in JS template (#5914) --- templates/extensions/javascript/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/extensions/javascript/index.js b/templates/extensions/javascript/index.js index 33837f73eae..3bd6dc6d4fb 100644 --- a/templates/extensions/javascript/index.js +++ b/templates/extensions/javascript/index.js @@ -5,7 +5,7 @@ * Reference PARAMETERS in your functions code with: * `process.env.` * Learn more about building extensions in the docs: - * https://firebase.google.com/docs/extensions/alpha/overview + * https://firebase.google.com/docs/extensions/publishers */ const functions = require("firebase-functions"); From 3b80ee25f225436f03352b1bd13dca330685fd9b Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 1 Jun 2023 11:57:42 -0400 Subject: [PATCH 037/320] Support Astro hybrid rendering (#5898) * Astro hybrid support * Middleware mode callout --- CHANGELOG.md | 1 + src/frameworks/astro/index.ts | 11 ++++++----- src/test/frameworks/astro/index.spec.ts | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f658a1f206..b42f3e7631d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Address additional cases where we were attempting to deploy a framework's development bundle (#5895) +- Support Astro hybrid rendering (#5898) diff --git a/src/frameworks/astro/index.ts b/src/frameworks/astro/index.ts index b7d7d804d39..02e5ad3daaa 100644 --- a/src/frameworks/astro/index.ts +++ b/src/frameworks/astro/index.ts @@ -25,7 +25,7 @@ export async function discover(dir: string): Promise { if (!getAstroVersion(dir)) return; const { output, publicDir: publicDirectory } = await getConfig(dir); return { - mayWantBackend: output === "server", + mayWantBackend: output !== "static", publicDirectory, }; } @@ -36,20 +36,21 @@ export async function build(cwd: string): Promise { const cli = getNodeModuleBin("astro", cwd); await warnIfCustomBuildScript(cwd, name, DEFAULT_BUILD_SCRIPT); const { output, adapter } = await getConfig(cwd); - if (output === "server" && adapter?.name !== "@astrojs/node") { + const wantsBackend = output !== "static"; + if (wantsBackend && adapter?.name !== "@astrojs/node") { throw new FirebaseError( - "Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter." + "Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter in middleware mode. https://docs.astro.build/en/guides/integrations-guide/node/" ); } const build = spawnSync(cli, ["build"], { cwd, stdio: "inherit" }); if (build.status !== 0) throw new FirebaseError("Unable to build your Astro app"); - return { wantsBackend: output === "server" }; + return { wantsBackend }; } export async function ɵcodegenPublicDirectory(root: string, dest: string) { const { outDir, output } = await getConfig(root); // output: "server" in astro.config builds "client" and "server" folders, otherwise assets are in top-level outDir - const assetPath = join(root, outDir, output === "server" ? "client" : ""); + const assetPath = join(root, outDir, output !== "static" ? "client" : ""); await copy(assetPath, dest); } diff --git a/src/test/frameworks/astro/index.spec.ts b/src/test/frameworks/astro/index.spec.ts index ef2289de609..7682b4b9404 100644 --- a/src/test/frameworks/astro/index.spec.ts +++ b/src/test/frameworks/astro/index.spec.ts @@ -268,7 +268,7 @@ describe("Astro", () => { await expect(build(cwd)).to.eventually.rejectedWith( FirebaseError, - "Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter." + "Deploying an Astro application with SSR on Firebase Hosting requires the @astrojs/node adapter in middleware mode. https://docs.astro.build/en/guides/integrations-guide/node/" ); }); From 48bdcb055170beef7ea3ccc8ff2ba2cf20b03b2b Mon Sep 17 00:00:00 2001 From: joehan Date: Thu, 1 Jun 2023 09:43:02 -0700 Subject: [PATCH 038/320] Switch ext:dev:init to default billingRequire to true (#5917) --- CHANGELOG.md | 1 + templates/extensions/extension.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b42f3e7631d..b7f96127751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,3 @@ - Address additional cases where we were attempting to deploy a framework's development bundle (#5895) +- Switch `ext:dev:init` to default 'billingRequired' to true in `extension.yaml` - Support Astro hybrid rendering (#5898) diff --git a/templates/extensions/extension.yaml b/templates/extensions/extension.yaml index e9792cb8a70..c1445250c44 100644 --- a/templates/extensions/extension.yaml +++ b/templates/extensions/extension.yaml @@ -19,7 +19,7 @@ sourceUrl: https://github.com/firebase/firebase-tools/tree/master/templates/exte # Specify whether a paid-tier billing plan is required to use your extension. # Learn more in the docs: https://firebase.google.com/docs/extensions/reference/extension-yaml#billing-required-field -billingRequired: false +billingRequired: true # In an `apis` field, list any Google APIs (like Cloud Translation, BigQuery, etc.) # required for your extension to operate. From a3a1da93b46bef00f06f39472dd5417b96908b90 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 1 Jun 2023 13:08:21 -0400 Subject: [PATCH 039/320] Get autoTokenSyncURL in simpleProxy sooner (#5894) Fixes #5852 --- CHANGELOG.md | 1 + src/frameworks/utils.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7f96127751..5ee9b7ed124 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Fix a bug preventing web framework's dev-mode from working out-of-box with Firebase Authentication. (#5894) - Address additional cases where we were attempting to deploy a framework's development bundle (#5895) - Switch `ext:dev:init` to default 'billingRequired' to true in `extension.yaml` - Support Astro hybrid rendering (#5898) diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index 265c742adc5..acf58c336cf 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -67,16 +67,16 @@ type RequestHandler = (req: IncomingMessage, res: ServerResponse) => Promise void) => { const { method, headers, url: path } = originalReq; if (!method || !path) { originalRes.end(); return; } - // If the path is a the auth token sync URL pass through to Cloud Functions - const firebaseDefaultsJSON = process.env.__FIREBASE_DEFAULTS__; - const authTokenSyncURL: string | undefined = - firebaseDefaultsJSON && JSON.parse(firebaseDefaultsJSON)._authTokenSyncURL; if (path === authTokenSyncURL) { return next(); } From a1a6cc98459e57c6ae46d1e352b3231910f4cd2b Mon Sep 17 00:00:00 2001 From: joehan Date: Thu, 1 Jun 2023 12:53:32 -0700 Subject: [PATCH 040/320] Remove LOCATION param from extension.yaml template. (#5925) * Switch ext:dev:init to default billingRequire to true * whitespace --- CHANGELOG.md | 1 + templates/extensions/extension.yaml | 53 ----------------------------- 2 files changed, 1 insertion(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ee9b7ed124..8647affa394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ - Fix a bug preventing web framework's dev-mode from working out-of-box with Firebase Authentication. (#5894) - Address additional cases where we were attempting to deploy a framework's development bundle (#5895) - Switch `ext:dev:init` to default 'billingRequired' to true in `extension.yaml` +- Remove `LOCATION` param from the `extensions.yaml` template for `ext:dev:init` - Support Astro hybrid rendering (#5898) diff --git a/templates/extensions/extension.yaml b/templates/extensions/extension.yaml index c1445250c44..83c44297726 100644 --- a/templates/extensions/extension.yaml +++ b/templates/extensions/extension.yaml @@ -39,8 +39,6 @@ resources: description: >- HTTP request-triggered function that responds with a specified greeting message properties: - # LOCATION is a user-configured parameter value specified by the user during installation. - location: ${LOCATION} # httpsTrigger is used for an HTTP triggered function. httpsTrigger: {} runtime: "nodejs16" @@ -58,54 +56,3 @@ params: default: Hello required: true immutable: false - - - param: LOCATION - label: Cloud Functions location - description: >- - Where do you want to deploy the functions created for this extension? - For help selecting a location, refer to the [location selection - guide](https://firebase.google.com/docs/functions/locations). - type: select - options: - - label: Iowa (us-central1) - value: us-central1 - - label: South Carolina (us-east1) - value: us-east1 - - label: Northern Virginia (us-east4) - value: us-east4 - - label: Los Angeles (us-west2) - value: us-west2 - - label: Salt Lake City (us-west3) - value: us-west3 - - label: Las Vegas (us-west4) - value: us-west4 - - label: Warsaw (europe-central2) - value: europe-central2 - - label: Belgium (europe-west1) - value: europe-west1 - - label: London (europe-west2) - value: europe-west2 - - label: Frankfurt (europe-west3) - value: europe-west3 - - label: Zurich (europe-west6) - value: europe-west6 - - label: Hong Kong (asia-east2) - value: asia-east2 - - label: Tokyo (asia-northeast1) - value: asia-northeast1 - - label: Osaka (asia-northeast2) - value: asia-northeast2 - - label: Seoul (asia-northeast3) - value: asia-northeast3 - - label: Mumbai (asia-south1) - value: asia-south1 - - label: Jakarta (asia-southeast2) - value: asia-southeast2 - - label: Montreal (northamerica-northeast1) - value: northamerica-northeast1 - - label: Sao Paulo (southamerica-east1) - value: southamerica-east1 - - label: Sydney (australia-southeast1) - value: australia-southeast1 - required: true - immutable: true From da5960aeafcf2141d3c96dafceddf5134c17d0c9 Mon Sep 17 00:00:00 2001 From: aalej Date: Fri, 2 Jun 2023 04:17:36 +0800 Subject: [PATCH 041/320] Improve error message raised when `--import` flag directory does not exist (#5905) * Improve error message raised when flag directory does not exist * Update CHANGELOG.md --------- Co-authored-by: joehan --- CHANGELOG.md | 1 + src/emulator/controller.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8647affa394..616b99ba2d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ - Fix a bug preventing web framework's dev-mode from working out-of-box with Firebase Authentication. (#5894) - Address additional cases where we were attempting to deploy a framework's development bundle (#5895) +- Improve error message raised when `--import` flag directory does not exist. (#5851) - Switch `ext:dev:init` to default 'billingRequired' to true in `extension.yaml` - Remove `LOCATION` param from the `extensions.yaml` template for `ext:dev:init` - Support Astro hybrid rendering (#5898) diff --git a/src/emulator/controller.ts b/src/emulator/controller.ts index 089250f00c7..2a0d2da2eab 100644 --- a/src/emulator/controller.ts +++ b/src/emulator/controller.ts @@ -186,6 +186,11 @@ export function shouldStart(options: Options, name: Emulators): boolean { } function findExportMetadata(importPath: string): ExportMetadata | undefined { + const pathExists = fs.existsSync(importPath); + if (!pathExists) { + throw new FirebaseError(`Directory "${importPath}" does not exist.`); + } + const pathIsDirectory = fs.lstatSync(importPath).isDirectory(); if (!pathIsDirectory) { return; From 2b6b19d319689404487cdff7d9ea446127dbba8c Mon Sep 17 00:00:00 2001 From: joehan Date: Thu, 1 Jun 2023 13:45:51 -0700 Subject: [PATCH 042/320] Clarify that sourceUri needs to be replaced (#5927) * Clarify that sourceUri needs to be replaced * TODO --- templates/extensions/extension.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/templates/extensions/extension.yaml b/templates/extensions/extension.yaml index 83c44297726..b34258ef9d8 100644 --- a/templates/extensions/extension.yaml +++ b/templates/extensions/extension.yaml @@ -1,7 +1,9 @@ # Learn detailed information about the fields of an extension.yaml file in the docs: # https://firebase.google.com/docs/extensions/reference/extension-yaml -name: greet-the-world # Identifier for your extension +# Identifier for your extension +# TODO: Replace this with an descriptive name for your extension. +name: greet-the-world version: 0.0.1 # Follow semver versioning specVersion: v1beta # Version of the Firebase Extensions specification @@ -14,8 +16,9 @@ description: >- license: Apache-2.0 # https://spdx.org/licenses/ -# Public URL for the source code of your extension -sourceUrl: https://github.com/firebase/firebase-tools/tree/master/templates/extensions +# Public URL for the source code of your extension. +# TODO: Replace this with your GitHub repo. +sourceUrl: https://github.com/ORG_OR_USER/REPO_NAME # Specify whether a paid-tier billing plan is required to use your extension. # Learn more in the docs: https://firebase.google.com/docs/extensions/reference/extension-yaml#billing-required-field From 708efef1685afb4ddc73d0597eb1caadf6417da7 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 1 Jun 2023 13:58:31 -0700 Subject: [PATCH 043/320] Export hosting-channel-deploy action (#5820) Co-authored-by: joehan --- src/commands/hosting-channel-deploy.ts | 263 +++++++++++++------------ 1 file changed, 133 insertions(+), 130 deletions(-) diff --git a/src/commands/hosting-channel-deploy.ts b/src/commands/hosting-channel-deploy.ts index 49e533830a5..343290236c9 100644 --- a/src/commands/hosting-channel-deploy.ts +++ b/src/commands/hosting-channel-deploy.ts @@ -46,149 +46,152 @@ export const command = new Command("hosting:channel:deploy [channelId]") .before(requireConfig) .before(requirePermissions, ["firebasehosting.sites.update"]) .before(requireHostingSite) - .action( - async ( - channelId: string, - options: Options & HostingOptions - ): Promise<{ [targetOrSite: string]: ChannelInfo }> => { - const projectId = needProjectId(options); - - // TODO: implement --open. - if (options.open) { - throw new FirebaseError("open is not yet implemented"); - } - - let expireTTL = DEFAULT_DURATION; - if (options.expires) { - expireTTL = calculateChannelExpireTTL(options.expires); - logger.debug(`Expires TTL: ${expireTTL}`); - } + .action(hostingChannelDeployAction); - // TODO: interactive prompt if channel doesn't exist - if (!channelId) { - throw new FirebaseError("channelID is currently required"); - } +/** + * Deploys to specified hosting channel. + * + * @param channelId ID of hosting channel to deploy to. + * @param options Deployment options + */ +export async function hostingChannelDeployAction( + channelId: string, + options: Options & HostingOptions +): Promise<{ [targetOrSite: string]: ChannelInfo }> { + const projectId = needProjectId(options); + + // TODO: implement --open. + if (options.open) { + throw new FirebaseError("open is not yet implemented"); + } - channelId = normalizeName(channelId); + let expireTTL = DEFAULT_DURATION; + if (options.expires) { + expireTTL = calculateChannelExpireTTL(options.expires); + logger.debug(`Expires TTL: ${expireTTL}`); + } - // Some normalizing to be very sure of this check. - if (channelId.toLowerCase().trim() === "live") { - throw new FirebaseError( - `Cannot deploy to the ${bold("live")} channel using this command. Please use ${bold( - yellow("firebase deploy") - )} instead.` - ); - } + // TODO: interactive prompt if channel doesn't exist + if (!channelId) { + throw new FirebaseError("channelID is currently required"); + } - if (options.only) { - // HACK: Re-use deploy in a rather ham-fisted way. - options.only = options.only - .split(",") - .map((o: string) => `hosting:${o}`) - .join(","); - } else { - // N.B. The hosting deploy code uses the only string to add all (and only) - // functions that are pinned to the only string. If we didn't set the - // only string here and only used the hosting deploy targets, we'd only - // be able to deploy *all* functions. - options.only = "hosting"; - } + channelId = normalizeName(channelId); - const sites: ChannelInfo[] = hostingConfig(options).map((config) => { - return { - target: config.target, - site: config.site, - url: "", - version: "", - expireTime: "", - }; - }); - - await Promise.all( - sites.map(async (siteInfo) => { - const site = siteInfo.site; - let chan = await getChannel(projectId, site, channelId); - if (chan) { - logger.debug("[hosting] found existing channel for site", site, chan); - const channelExpires = Boolean(chan.expireTime); - if (!channelExpires && options.expires) { - // If the channel doesn't expire, but the user provided a TTL, update the channel. - chan = await updateChannelTtl(projectId, site, channelId, expireTTL); - } else if (channelExpires) { - // If the channel expires, calculate the time remaining to maybe update the channel. - const channelTimeRemaining = new Date(chan.expireTime).getTime() - Date.now(); - // If the user explicitly gave us a time OR the time remaining is less than the new TTL: - if (options.expires || channelTimeRemaining < expireTTL) { - chan = await updateChannelTtl(projectId, site, channelId, expireTTL); - logger.debug("[hosting] updated TTL for existing channel for site", site, chan); - } - } - } else { - chan = await createChannel(projectId, site, channelId, expireTTL); - logger.debug("[hosting] created new channnel for site", site, chan); - logLabeledSuccess( - LOG_TAG, - `Channel ${bold(channelId)} has been created on site ${bold(site)}.` - ); - } - siteInfo.url = chan.url; - siteInfo.expireTime = chan.expireTime; - return; - }) - ); - - const { hosting } = await deploy(["hosting"], options, { hostingChannel: channelId }); - - // The version names are returned in the hosting key of the deploy result. - // - // If there is only one element it is returned as a string, otherwise it - // is an array of strings. Not sure why it's done that way, but that's - // something we can't change because it is in the deploy output in json. - // - // The code below turns it back to an array of version names. - const versionNames: Array = []; - if (typeof hosting === "string") { - versionNames.push(hosting); - } else if (Array.isArray(hosting)) { - hosting.forEach((version) => { - versionNames.push(version); - }); - } + // Some normalizing to be very sure of this check. + if (channelId.toLowerCase().trim() === "live") { + throw new FirebaseError( + `Cannot deploy to the ${bold("live")} channel using this command. Please use ${bold( + yellow("firebase deploy") + )} instead.` + ); + } - if (options.authorizedDomains) { - await syncAuthState(projectId, sites); - } else { - logger.debug( - `skipping syncAuthState since authorizedDomains is ${options.authorizedDomains}` - ); - } + if (options.only) { + // HACK: Re-use deploy in a rather ham-fisted way. + options.only = options.only + .split(",") + .map((o: string) => `hosting:${o}`) + .join(","); + } else { + // N.B. The hosting deploy code uses the only string to add all (and only) + // functions that are pinned to the only string. If we didn't set the + // only string here and only used the hosting deploy targets, we'd only + // be able to deploy *all* functions. + options.only = "hosting"; + } - logger.info(); - const deploys: { [key: string]: ChannelInfo } = {}; - sites.forEach((d) => { - deploys[d.target || d.site] = d; - let expires = ""; - if (d.expireTime) { - expires = `[expires ${bold(datetimeString(new Date(d.expireTime)))}]`; - } - const versionPrefix = `sites/${d.site}/versions/`; - const versionName = versionNames.find((v) => { - return v.startsWith(versionPrefix); - }); - let version = ""; - if (versionName) { - d.version = versionName.replace(versionPrefix, ""); - version = ` [version ${bold(d.version)}]`; + const sites: ChannelInfo[] = hostingConfig(options).map((config) => { + return { + target: config.target, + site: config.site, + url: "", + version: "", + expireTime: "", + }; + }); + + await Promise.all( + sites.map(async (siteInfo) => { + const site = siteInfo.site; + let chan = await getChannel(projectId, site, channelId); + if (chan) { + logger.debug("[hosting] found existing channel for site", site, chan); + const channelExpires = Boolean(chan.expireTime); + if (!channelExpires && options.expires) { + // If the channel doesn't expire, but the user provided a TTL, update the channel. + chan = await updateChannelTtl(projectId, site, channelId, expireTTL); + } else if (channelExpires) { + // If the channel expires, calculate the time remaining to maybe update the channel. + const channelTimeRemaining = new Date(chan.expireTime).getTime() - Date.now(); + // If the user explicitly gave us a time OR the time remaining is less than the new TTL: + if (options.expires || channelTimeRemaining < expireTTL) { + chan = await updateChannelTtl(projectId, site, channelId, expireTTL); + logger.debug("[hosting] updated TTL for existing channel for site", site, chan); + } } + } else { + chan = await createChannel(projectId, site, channelId, expireTTL); + logger.debug("[hosting] created new channnel for site", site, chan); logLabeledSuccess( LOG_TAG, - `Channel URL (${bold(d.site || d.target || "")}): ${d.url} ${expires}${version}` + `Channel ${bold(channelId)} has been created on site ${bold(site)}.` ); - }); - return deploys; - } + } + siteInfo.url = chan.url; + siteInfo.expireTime = chan.expireTime; + return; + }) ); + const { hosting } = await deploy(["hosting"], options, { hostingChannel: channelId }); + + // The version names are returned in the hosting key of the deploy result. + // + // If there is only one element it is returned as a string, otherwise it + // is an array of strings. Not sure why it's done that way, but that's + // something we can't change because it is in the deploy output in json. + // + // The code below turns it back to an array of version names. + const versionNames: Array = []; + if (typeof hosting === "string") { + versionNames.push(hosting); + } else if (Array.isArray(hosting)) { + hosting.forEach((version) => { + versionNames.push(version); + }); + } + + if (options.authorizedDomains) { + await syncAuthState(projectId, sites); + } else { + logger.debug(`skipping syncAuthState since authorizedDomains is ${options.authorizedDomains}`); + } + + logger.info(); + const deploys: { [key: string]: ChannelInfo } = {}; + sites.forEach((d) => { + deploys[d.target || d.site] = d; + let expires = ""; + if (d.expireTime) { + expires = `[expires ${bold(datetimeString(new Date(d.expireTime)))}]`; + } + const versionPrefix = `sites/${d.site}/versions/`; + const versionName = versionNames.find((v) => { + return v.startsWith(versionPrefix); + }); + let version = ""; + if (versionName) { + d.version = versionName.replace(versionPrefix, ""); + version = ` [version ${bold(d.version)}]`; + } + logLabeledSuccess( + LOG_TAG, + `Channel URL (${bold(d.site || d.target || "")}): ${d.url} ${expires}${version}` + ); + }); + return deploys; +} /** * Helper function to sync authorized domains for deployed sites. * @param projectId the project id. From ac21ab3cf18eba6f6f06b932ee7b04d84d02d054 Mon Sep 17 00:00:00 2001 From: aalej Date: Fri, 2 Jun 2023 05:33:30 +0800 Subject: [PATCH 044/320] Fix issue where a user is created when empty email and password is passed (#5906) * Fix issue where a user is created when passing an empty email and password * Fix issue where a user is created when passing an empty email and password --------- Co-authored-by: joehan --- CHANGELOG.md | 1 + src/emulator/auth/operations.ts | 4 ++-- src/test/emulators/auth/signUp.spec.ts | 11 +++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 616b99ba2d6..ed5acc5674e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ - Fix a bug preventing web framework's dev-mode from working out-of-box with Firebase Authentication. (#5894) - Address additional cases where we were attempting to deploy a framework's development bundle (#5895) +- Fixes issue where Authentication emulator creates a user if empty email and empty password is provided. (#5639) - Improve error message raised when `--import` flag directory does not exist. (#5851) - Switch `ext:dev:init` to default 'billingRequired' to true in `extension.yaml` - Remove `LOCATION` param from the `extensions.yaml` template for `ext:dev:init` diff --git a/src/emulator/auth/operations.ts b/src/emulator/auth/operations.ts index cde34a11853..9cc1d4619c3 100644 --- a/src/emulator/auth/operations.ts +++ b/src/emulator/auth/operations.ts @@ -198,13 +198,13 @@ async function signUp( } } - if (reqBody.email) { + if (typeof reqBody.email === "string") { assert(isValidEmailAddress(reqBody.email), "INVALID_EMAIL"); const email = canonicalizeEmailAddress(reqBody.email); assert(!state.getUserByEmail(email), "EMAIL_EXISTS"); updates.email = email; } - if (reqBody.password) { + if (typeof reqBody.password === "string") { assert( reqBody.password.length >= PASSWORD_MIN_LENGTH, `WEAK_PASSWORD : Password should be at least ${PASSWORD_MIN_LENGTH} characters` diff --git a/src/test/emulators/auth/signUp.spec.ts b/src/test/emulators/auth/signUp.spec.ts index bb7d6787fd8..a69b12d908e 100644 --- a/src/test/emulators/auth/signUp.spec.ts +++ b/src/test/emulators/auth/signUp.spec.ts @@ -40,6 +40,17 @@ describeAuthEmulator("accounts:signUp", ({ authApi }) => { }); }); + it("should throw error if empty email and password is provided", async () => { + await authApi() + .post("/identitytoolkit.googleapis.com/v1/accounts:signUp") + .send({ email: "", password: "" }) + .query({ key: "fake-api-key" }) + .then((res) => { + expectStatusCode(400, res); + expect(res.body.error).to.have.property("message").equals("INVALID_EMAIL"); + }); + }); + it("should issue idToken and refreshToken on anon signUp", async () => { await authApi() .post("/identitytoolkit.googleapis.com/v1/accounts:signUp") From 0261dc813c6f72229bc2ff2e1fa767c17fe1ca3b Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 1 Jun 2023 18:23:54 -0400 Subject: [PATCH 045/320] Continue on 404, baseUrl for Next rewrites (#5923) * Test the effective firebase.json * Using aliases for the emulator test * Caught that baseUrl wasn't being returned correctly by NextJS * Adding back in continue on 404 for the emulators, fixes #5840 * Switch to using logger rather than console.log * Cleanup the test script * Test combination of Cloud Function rewrites and web frameworks * Web Frameworks rewrites/redirects/headers should only come before existing if there's a baseUrl * Move basePath to build so we can use it sooner --- CHANGELOG.md | 3 + .../webframeworks-deploy-tests/.firebaserc | 19 +- .../webframeworks-deploy-tests/firebase.json | 45 +- .../functions/.gitignore | 1 + .../functions/index.js | 5 + .../functions/package-lock.json | 10865 ++++++++++++++++ .../functions/package.json | 23 + .../nextjs/next.config.js | 22 + scripts/webframeworks-deploy-tests/run.sh | 13 +- scripts/webframeworks-deploy-tests/tests.ts | 145 +- src/frameworks/angular/index.ts | 23 +- src/frameworks/index.ts | 75 +- src/frameworks/interfaces.ts | 8 +- src/frameworks/next/index.ts | 43 +- src/frameworks/nuxt/index.ts | 14 +- src/frameworks/utils.ts | 30 +- 16 files changed, 11242 insertions(+), 92 deletions(-) create mode 100644 scripts/webframeworks-deploy-tests/functions/.gitignore create mode 100644 scripts/webframeworks-deploy-tests/functions/index.js create mode 100644 scripts/webframeworks-deploy-tests/functions/package-lock.json create mode 100644 scripts/webframeworks-deploy-tests/functions/package.json diff --git a/CHANGELOG.md b/CHANGELOG.md index ed5acc5674e..6822691b7c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ - Fix a bug preventing web framework's dev-mode from working out-of-box with Firebase Authentication. (#5894) - Address additional cases where we were attempting to deploy a framework's development bundle (#5895) +- NextJS rewrites should be prefixed with the basePath defined in next.config.js (#5923) +- Web Frameworks emulators will again respect existing Cloud Functions rewrites (#5923) +- Web Frameworks rewrites/redirects/headers will only prepend those in firebase.json if there's a baseUrl (#5923) - Fixes issue where Authentication emulator creates a user if empty email and empty password is provided. (#5639) - Improve error message raised when `--import` flag directory does not exist. (#5851) - Switch `ext:dev:init` to default 'billingRequired' to true in `extension.yaml` diff --git a/scripts/webframeworks-deploy-tests/.firebaserc b/scripts/webframeworks-deploy-tests/.firebaserc index 0967ef424bc..17a020da167 100644 --- a/scripts/webframeworks-deploy-tests/.firebaserc +++ b/scripts/webframeworks-deploy-tests/.firebaserc @@ -1 +1,18 @@ -{} +{ + "projects": { + "default": "nextjs-demo-73e34" + }, + "targets": { + "demo-123": { + "hosting": { + "angular": [ + "demo-angular" + ], + "nextjs": [ + "demo-nextjs" + ] + } + } + }, + "etags": {} +} diff --git a/scripts/webframeworks-deploy-tests/firebase.json b/scripts/webframeworks-deploy-tests/firebase.json index c37e2d01e99..a59a94f84a8 100644 --- a/scripts/webframeworks-deploy-tests/firebase.json +++ b/scripts/webframeworks-deploy-tests/firebase.json @@ -1,9 +1,40 @@ { - "hosting": [{ - "site": "demo-nextjs", - "source": "nextjs" - }, { - "site": "demo-angular", - "source": "angular" - }] + "hosting": [ + { + "target": "nextjs", + "source": "nextjs", + "frameworksBackend": { + "maxInstances": 1, + "region": "asia-east1" + }, + "rewrites": [{ + "source": "helloWorld", + "function": "helloWorld" + }] + }, + { + "target": "angular", + "source": "angular", + "frameworksBackend": { + "maxInstances": 1, + "region": "europe-west1" + }, + "rewrites": [{ + "source": "helloWorld", + "function": "helloWorld" + }] + } + ], + "functions": [ + { + "source": "functions", + "codebase": "default", + "ignore": [ + "node_modules", + ".git", + "firebase-debug.log", + "firebase-debug.*.log" + ] + } + ] } diff --git a/scripts/webframeworks-deploy-tests/functions/.gitignore b/scripts/webframeworks-deploy-tests/functions/.gitignore new file mode 100644 index 00000000000..40b878db5b1 --- /dev/null +++ b/scripts/webframeworks-deploy-tests/functions/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/scripts/webframeworks-deploy-tests/functions/index.js b/scripts/webframeworks-deploy-tests/functions/index.js new file mode 100644 index 00000000000..ebf396726e7 --- /dev/null +++ b/scripts/webframeworks-deploy-tests/functions/index.js @@ -0,0 +1,5 @@ +import { onRequest } from "firebase-functions/v2/https"; + +export const helloWorld = onRequest((request, response) => { + response.send("Hello from Firebase!"); +}); diff --git a/scripts/webframeworks-deploy-tests/functions/package-lock.json b/scripts/webframeworks-deploy-tests/functions/package-lock.json new file mode 100644 index 00000000000..9ebba9bb98e --- /dev/null +++ b/scripts/webframeworks-deploy-tests/functions/package-lock.json @@ -0,0 +1,10865 @@ +{ + "name": "functions", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "functions", + "dependencies": { + "firebase-admin": "^11.8.0", + "firebase-functions": "^4.3.1" + }, + "devDependencies": { + "firebase-functions-test": "^3.1.0" + }, + "engines": { + "node": "18" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.3.tgz", + "integrity": "sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.1.tgz", + "integrity": "sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.22.0", + "@babel/helper-compilation-targets": "^7.22.1", + "@babel/helper-module-transforms": "^7.22.1", + "@babel/helpers": "^7.22.0", + "@babel/parser": "^7.22.0", + "@babel/template": "^7.21.9", + "@babel/traverse": "^7.22.1", + "@babel/types": "^7.22.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "peer": true + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/@babel/generator": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.3.tgz", + "integrity": "sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.22.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz", + "integrity": "sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.22.0", + "@babel/helper-validator-option": "^7.21.0", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "peer": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz", + "integrity": "sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", + "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.21.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.1.tgz", + "integrity": "sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.1", + "@babel/helper-module-imports": "^7.21.4", + "@babel/helper-simple-access": "^7.21.5", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.21.9", + "@babel/traverse": "^7.22.1", + "@babel/types": "^7.22.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", + "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", + "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.21.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", + "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.3.tgz", + "integrity": "sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.21.9", + "@babel/traverse": "^7.22.1", + "@babel/types": "^7.22.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.4.tgz", + "integrity": "sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==", + "devOptional": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.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==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "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==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", + "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.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==", + "dev": true, + "peer": true, + "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-typescript": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.21.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz", + "integrity": "sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "@babel/parser": "^7.21.9", + "@babel/types": "^7.21.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.22.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.4.tgz", + "integrity": "sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.22.3", + "@babel/helper-environment-visitor": "^7.22.1", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.22.4", + "@babel/types": "^7.22.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/@babel/types": { + "version": "7.22.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.4.tgz", + "integrity": "sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.21.5", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "peer": true + }, + "node_modules/@fastify/busboy": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", + "integrity": "sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==", + "dependencies": { + "text-decoding": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", + "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", + "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + }, + "node_modules/@firebase/component": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", + "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "dependencies": { + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.14.4.tgz", + "integrity": "sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==", + "dependencies": { + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz", + "integrity": "sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/database": "0.14.4", + "@firebase/database-types": "0.10.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz", + "integrity": "sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==", + "dependencies": { + "@firebase/app-types": "0.9.0", + "@firebase/util": "1.9.3" + } + }, + "node_modules/@firebase/logger": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", + "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/util": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", + "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@google-cloud/firestore": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-6.6.1.tgz", + "integrity": "sha512-Z41j2h0mrgBH9qNIVmbRLqGKc6XmdJtWipeKwdnGa/bPTP1gn2SGTrYyWnpfsLMEtzKSYieHPSkAFp5kduF2RA==", + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "functional-red-black-tree": "^1.0.1", + "google-gax": "^3.5.7", + "protobufjs": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@google-cloud/paginator": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", + "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "optional": true, + "dependencies": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", + "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", + "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@google-cloud/storage": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.10.1.tgz", + "integrity": "sha512-EtLlT0YbXtrbUxaNbEfTyTytrjELtl4i42flf8COg+Hu5+apdNjsFO9XEY39wshxAuVjLf4fCSm7GTSW+BD3gQ==", + "optional": true, + "dependencies": { + "@google-cloud/paginator": "^3.0.7", + "@google-cloud/projectify": "^3.0.0", + "@google-cloud/promisify": "^3.0.0", + "abort-controller": "^3.0.0", + "async-retry": "^1.3.3", + "compressible": "^2.0.12", + "duplexify": "^4.0.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "gaxios": "^5.0.0", + "google-auth-library": "^8.0.1", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "retry-request": "^5.0.0", + "teeny-request": "^8.0.0", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@google-cloud/storage/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz", + "integrity": "sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==", + "optional": true, + "dependencies": { + "@grpc/proto-loader": "^0.7.0", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.7.tgz", + "integrity": "sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==", + "optional": true, + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "peer": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "peer": true, + "dependencies": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "peer": true, + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "dev": true, + "peer": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dev": true, + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true, + "peer": true + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", + "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", + "optional": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true, + "peer": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "peer": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.2.0.tgz", + "integrity": "sha512-OPwQlEdg40HAj5KNF8WW6q2KG4Z+cBCZb3m4ninfTZKaBmbIJodviQsDBoYMPHkOyJJMHnOJo5j2+LKDOhOACg==", + "dev": true, + "peer": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "optional": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.0.tgz", + "integrity": "sha512-TBOjqAGf0hmaqRwpii5LLkJLg7c6OMm4nHLmpsUxwk9bBHtoTC6dAHdVWdGv4TBxj2CZOZY8Xfq8WmfoVi7n4Q==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz", + "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "optional": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true, + "peer": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "optional": true + }, + "node_modules/@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "optional": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "optional": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "optional": true + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "optional": true + }, + "node_modules/@types/node": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", + "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "peer": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "optional": true, + "dependencies": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true, + "peer": true + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true, + "peer": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "optional": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "optional": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "optional": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "peer": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "optional": true, + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "peer": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.5.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "optional": true + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "peer": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "peer": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "peer": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001492", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001492.tgz", + "integrity": "sha512-2efF8SAZwgAX1FJr87KWhvuJxnGJKOnctQa8xLOskAXNXq8oiuqgl6u1kk3fFpsp3GgvzlRjiK1sl63hNtFADw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "optional": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true, + "peer": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "devOptional": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "peer": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true, + "peer": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "optional": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "devOptional": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "peer": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "optional": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.417", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.417.tgz", + "integrity": "sha512-8rY8HdCxuSVY8wku3i/eDac4g1b4cSbruzocenrqBlzqruAZYHjQCHIjC66dLR9DXhEHTojsC4EjhZ8KmzwXqA==", + "dev": true, + "peer": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "devOptional": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "optional": true + }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "optional": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "peer": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "optional": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "optional": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "optional": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "optional": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "devOptional": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "optional": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "optional": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "optional": true + }, + "node_modules/fast-text-encoding": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", + "optional": true + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "peer": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "peer": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/firebase-admin": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.9.0.tgz", + "integrity": "sha512-My7qrInVZFmImX8aTulrp9kgY6d88Wn+ie8UIXKzZ3SJqQQhDwFT7Q3pgQXK9RfdsUtcxJJ3rCK7MWBm4GGtuw==", + "dependencies": { + "@fastify/busboy": "^1.2.1", + "@firebase/database-compat": "^0.3.4", + "@firebase/database-types": "^0.10.4", + "@types/node": ">=12.12.47", + "jsonwebtoken": "^9.0.0", + "jwks-rsa": "^3.0.1", + "node-forge": "^1.3.1", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "@google-cloud/firestore": "^6.6.0", + "@google-cloud/storage": "^6.9.5" + } + }, + "node_modules/firebase-functions": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.4.0.tgz", + "integrity": "sha512-Vdkr9/y/UKQez//cPm2Iu/9CeayqQ2tQF6o3KXozDDBokK9AOlAalVHImCpKo6nWptT/ncZ8djJFk5cR8l+E+A==", + "dependencies": { + "@types/cors": "^2.8.5", + "@types/express": "4.17.3", + "cors": "^2.8.5", + "express": "^4.17.1", + "node-fetch": "^2.6.7", + "protobufjs": "^7.2.2" + }, + "bin": { + "firebase-functions": "lib/bin/firebase-functions.js" + }, + "engines": { + "node": ">=14.10.0" + }, + "peerDependencies": { + "firebase-admin": "^10.0.0 || ^11.0.0" + } + }, + "node_modules/firebase-functions-test": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/firebase-functions-test/-/firebase-functions-test-3.1.0.tgz", + "integrity": "sha512-yfm9ToguShxmRXb7TINN88zE2bM9gsBbs7vMWVKJAxGcl/n1f/U0sT5k2yho676QIcSqXVSjCONU8W4cUEL+Sw==", + "dev": true, + "dependencies": { + "@types/lodash": "^4.14.104", + "lodash": "^4.17.5", + "ts-deepmerge": "^2.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "firebase-admin": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", + "firebase-functions": ">=4.3.0", + "jest": ">=28.0.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "devOptional": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "optional": true + }, + "node_modules/gaxios": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.0.tgz", + "integrity": "sha512-aezGIjb+/VfsJtIcHGcBSerNEDdfdHeMros+RbYbGpmonKWQCOVOes0LVZhn1lDtIgq55qq0HaxymIoae3Fl/A==", + "optional": true, + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gcp-metadata": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.2.0.tgz", + "integrity": "sha512-aFhhvvNycky2QyhG+dcfEdHBF0FRbYcf39s6WNHUDysKSrbJ5vuFbjydxBcmewtXeV248GP8dWT3ByPNxsyHCw==", + "optional": true, + "dependencies": { + "gaxios": "^5.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/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==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "devOptional": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "devOptional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "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, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/google-auth-library": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.8.0.tgz", + "integrity": "sha512-0iJn7IDqObDG5Tu9Tn2WemmJ31ksEa96IyK0J0OZCpTh6CrC6FrattwKX87h3qKVuprCJpdOGKc1Xi8V0kMh8Q==", + "optional": true, + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^5.0.0", + "gcp-metadata": "^5.2.0", + "gtoken": "^6.1.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/google-gax": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.0.tgz", + "integrity": "sha512-2fyb61vWxUonHiArRNJQmE4tx5oY1ni8VPo08fzII409vDSCWG7apDX4qNOQ2GXXT82gLBn3d3P1Dydh7pWjyw==", + "optional": true, + "dependencies": { + "@grpc/grpc-js": "~1.8.0", + "@grpc/proto-loader": "^0.7.0", + "@types/long": "^4.0.0", + "@types/rimraf": "^3.0.2", + "abort-controller": "^3.0.0", + "duplexify": "^4.0.0", + "fast-text-encoding": "^1.0.3", + "google-auth-library": "^8.0.2", + "is-stream-ended": "^0.1.4", + "node-fetch": "^2.6.1", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^1.0.0", + "protobufjs": "7.2.3", + "protobufjs-cli": "1.1.1", + "retry-request": "^5.0.0" + }, + "bin": { + "compileProtos": "build/tools/compileProtos.js", + "minifyProtoJson": "build/tools/minify.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/google-p12-pem": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", + "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", + "optional": true, + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "devOptional": true + }, + "node_modules/gtoken": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", + "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", + "optional": true, + "dependencies": { + "gaxios": "^5.0.1", + "google-p12-pem": "^4.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "peer": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "optional": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "peer": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "devOptional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "peer": true + }, + "node_modules/is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dev": true, + "peer": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "devOptional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "optional": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "peer": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "peer": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", + "import-local": "^3.0.2", + "jest-cli": "^29.5.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "peer": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "peer": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "dev": true, + "peer": true, + "dependencies": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", + "dev": true, + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "dev": true, + "peer": true, + "dependencies": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "peer": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "optional": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", + "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "optional": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "optional": true, + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "peer": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "optional": true, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwks-rsa": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz", + "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==", + "dependencies": { + "@types/express": "^4.17.14", + "@types/jsonwebtoken": "^9.0.0", + "debug": "^4.3.4", + "jose": "^4.10.4", + "limiter": "^1.1.5", + "lru-memoizer": "^2.1.4" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jwks-rsa/node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/jwks-rsa/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/jwks-rsa/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "optional": true, + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "optional": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "peer": true + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "optional": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "optional": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "optional": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-memoizer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", + "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "~4.0.0" + } + }, + "node_modules/lru-memoizer/node_modules/lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/lru-memoizer/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "peer": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "peer": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "optional": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "optional": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "optional": true + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "optional": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "optional": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "peer": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "peer": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "peer": true + }, + "node_modules/node-releases": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "dev": true, + "peer": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "peer": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "peer": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "optional": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "devOptional": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "peer": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "peer": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true, + "peer": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "peer": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "optional": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "peer": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proto3-json-serializer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", + "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", + "optional": true, + "dependencies": { + "protobufjs": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protobufjs": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz", + "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protobufjs-cli": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", + "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", + "optional": true, + "dependencies": { + "chalk": "^4.0.0", + "escodegen": "^1.13.0", + "espree": "^9.0.0", + "estraverse": "^5.1.0", + "glob": "^8.0.0", + "jsdoc": "^4.0.0", + "minimist": "^1.2.0", + "semver": "^7.1.2", + "tmp": "^0.2.1", + "uglify-js": "^3.7.7" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "protobufjs": "^7.0.0" + } + }, + "node_modules/protobufjs-cli/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/protobufjs-cli/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/protobufjs-cli/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "optional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protobufjs-cli/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/protobufjs/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "node_modules/pure-rand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", + "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "peer": true + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true, + "peer": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "optional": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "peer": true, + "dependencies": { + "is-core-module": "^2.11.0", + "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/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "peer": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/retry-request": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", + "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", + "optional": true, + "dependencies": { + "debug": "^4.1.1", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/retry-request/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/retry-request/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "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, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "peer": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "peer": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "peer": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "peer": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "optional": true, + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "optional": true + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "peer": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "devOptional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "devOptional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", + "optional": true + }, + "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==", + "devOptional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/teeny-request": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", + "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "optional": true, + "dependencies": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "peer": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-decoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", + "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "optional": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "peer": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "peer": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-deepmerge": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-2.0.7.tgz", + "integrity": "sha512-3phiGcxPSSR47RBubQxPoZ+pqXsEsozLo4G4AlSrsMKTFg9TA3l+3he5BqpUi9wiuDbaHWXH/amlzQ49uEdXtg==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", + "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "optional": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "optional": true + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "optional": true + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "optional": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "peer": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "peer": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "peer": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "optional": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "devOptional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "devOptional": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "devOptional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "devOptional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "dev": true, + "peer": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.3.tgz", + "integrity": "sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==", + "dev": true, + "peer": true + }, + "@babel/core": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.1.tgz", + "integrity": "sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==", + "dev": true, + "peer": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.22.0", + "@babel/helper-compilation-targets": "^7.22.1", + "@babel/helper-module-transforms": "^7.22.1", + "@babel/helpers": "^7.22.0", + "@babel/parser": "^7.22.0", + "@babel/template": "^7.21.9", + "@babel/traverse": "^7.22.1", + "@babel/types": "^7.22.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "dependencies": { + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "peer": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + } + } + }, + "@babel/generator": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.3.tgz", + "integrity": "sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.22.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz", + "integrity": "sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/compat-data": "^7.22.0", + "@babel/helper-validator-option": "^7.21.0", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "peer": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "peer": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz", + "integrity": "sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==", + "dev": true, + "peer": true + }, + "@babel/helper-function-name": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "dev": true, + "peer": true, + "requires": { + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", + "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.21.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.1.tgz", + "integrity": "sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.1", + "@babel/helper-module-imports": "^7.21.4", + "@babel/helper-simple-access": "^7.21.5", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.21.9", + "@babel/traverse": "^7.22.1", + "@babel/types": "^7.22.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", + "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", + "dev": true, + "peer": true + }, + "@babel/helper-simple-access": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", + "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.21.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", + "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "dev": true, + "peer": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "peer": true + }, + "@babel/helper-validator-option": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "dev": true, + "peer": true + }, + "@babel/helpers": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.3.tgz", + "integrity": "sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==", + "dev": true, + "peer": true, + "requires": { + "@babel/template": "^7.21.9", + "@babel/traverse": "^7.22.1", + "@babel/types": "^7.22.3" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.22.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.4.tgz", + "integrity": "sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==", + "devOptional": true + }, + "@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==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", + "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "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==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/template": { + "version": "7.21.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz", + "integrity": "sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.21.4", + "@babel/parser": "^7.21.9", + "@babel/types": "^7.21.5" + } + }, + "@babel/traverse": { + "version": "7.22.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.4.tgz", + "integrity": "sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.22.3", + "@babel/helper-environment-visitor": "^7.22.1", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.22.4", + "@babel/types": "^7.22.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + } + } + }, + "@babel/types": { + "version": "7.22.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.4.tgz", + "integrity": "sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-string-parser": "^7.21.5", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "peer": true + }, + "@fastify/busboy": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", + "integrity": "sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==", + "requires": { + "text-decoding": "^1.0.0" + } + }, + "@firebase/app-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", + "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + }, + "@firebase/auth-interop-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", + "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + }, + "@firebase/component": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", + "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "requires": { + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "@firebase/database": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.14.4.tgz", + "integrity": "sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==", + "requires": { + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "@firebase/database-compat": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz", + "integrity": "sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==", + "requires": { + "@firebase/component": "0.6.4", + "@firebase/database": "0.14.4", + "@firebase/database-types": "0.10.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "@firebase/database-types": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz", + "integrity": "sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==", + "requires": { + "@firebase/app-types": "0.9.0", + "@firebase/util": "1.9.3" + } + }, + "@firebase/logger": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", + "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@firebase/util": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", + "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "requires": { + "tslib": "^2.1.0" + } + }, + "@google-cloud/firestore": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-6.6.1.tgz", + "integrity": "sha512-Z41j2h0mrgBH9qNIVmbRLqGKc6XmdJtWipeKwdnGa/bPTP1gn2SGTrYyWnpfsLMEtzKSYieHPSkAFp5kduF2RA==", + "optional": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "functional-red-black-tree": "^1.0.1", + "google-gax": "^3.5.7", + "protobufjs": "^7.0.0" + } + }, + "@google-cloud/paginator": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", + "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "optional": true, + "requires": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + } + }, + "@google-cloud/projectify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", + "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", + "optional": true + }, + "@google-cloud/promisify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", + "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", + "optional": true + }, + "@google-cloud/storage": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.10.1.tgz", + "integrity": "sha512-EtLlT0YbXtrbUxaNbEfTyTytrjELtl4i42flf8COg+Hu5+apdNjsFO9XEY39wshxAuVjLf4fCSm7GTSW+BD3gQ==", + "optional": true, + "requires": { + "@google-cloud/paginator": "^3.0.7", + "@google-cloud/projectify": "^3.0.0", + "@google-cloud/promisify": "^3.0.0", + "abort-controller": "^3.0.0", + "async-retry": "^1.3.3", + "compressible": "^2.0.12", + "duplexify": "^4.0.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "gaxios": "^5.0.0", + "google-auth-library": "^8.0.1", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "retry-request": "^5.0.0", + "teeny-request": "^8.0.0", + "uuid": "^8.0.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true + } + } + }, + "@grpc/grpc-js": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz", + "integrity": "sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==", + "optional": true, + "requires": { + "@grpc/proto-loader": "^0.7.0", + "@types/node": ">=12.12.47" + } + }, + "@grpc/proto-loader": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.7.tgz", + "integrity": "sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==", + "optional": true, + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^17.7.2" + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "peer": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "peer": true + }, + "@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0" + } + }, + "@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "peer": true, + "requires": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + } + }, + "@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "peer": true, + "requires": { + "jest-get-type": "^29.4.3" + } + }, + "@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "dev": true, + "peer": true, + "requires": { + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + } + }, + "@jest/globals": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" + } + }, + "@jest/reporters": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "dev": true, + "peer": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + } + }, + "@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dev": true, + "peer": true, + "requires": { + "@sinclair/typebox": "^0.25.16" + } + }, + "@jest/source-map": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", + "dev": true, + "peer": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + } + }, + "@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "peer": true, + "requires": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "peer": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "peer": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true, + "peer": true + } + } + }, + "@jsdoc/salty": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", + "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", + "optional": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true, + "peer": true + }, + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "peer": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.2.0.tgz", + "integrity": "sha512-OPwQlEdg40HAj5KNF8WW6q2KG4Z+cBCZb3m4ninfTZKaBmbIJodviQsDBoYMPHkOyJJMHnOJo5j2+LKDOhOACg==", + "dev": true, + "peer": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "optional": true + }, + "@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "dev": true, + "peer": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "peer": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.0.tgz", + "integrity": "sha512-TBOjqAGf0hmaqRwpii5LLkJLg7c6OMm4nHLmpsUxwk9bBHtoTC6dAHdVWdGv4TBxj2CZOZY8Xfq8WmfoVi7n4Q==", + "dev": true, + "peer": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz", + "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "optional": true, + "requires": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true, + "peer": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "peer": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "peer": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==", + "requires": { + "@types/node": "*" + } + }, + "@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "optional": true + }, + "@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true + }, + "@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "optional": true + }, + "@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "optional": true, + "requires": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "optional": true + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "optional": true + }, + "@types/node": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", + "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" + }, + "@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "peer": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "optional": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true, + "peer": true + }, + "@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "peer": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true, + "peer": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "optional": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "optional": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "optional": true, + "requires": {} + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "peer": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "devOptional": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "peer": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "optional": true + }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "optional": true, + "requires": { + "retry": "0.13.1" + } + }, + "babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "peer": true, + "requires": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "peer": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "peer": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "peer": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "peer": true, + "requires": { + "babel-plugin-jest-hoist": "^29.5.0", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "optional": true + }, + "bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "optional": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "optional": true + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "peer": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", + "dev": true, + "peer": true, + "requires": { + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "peer": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "peer": true + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "peer": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "peer": true + }, + "caniuse-lite": { + "version": "1.0.30001492", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001492.tgz", + "integrity": "sha512-2efF8SAZwgAX1FJr87KWhvuJxnGJKOnctQa8xLOskAXNXq8oiuqgl6u1kk3fFpsp3GgvzlRjiK1sl63hNtFADw==", + "dev": true, + "peer": true + }, + "catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "optional": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "peer": true + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "peer": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true, + "peer": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "devOptional": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "peer": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true, + "peer": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "optional": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "devOptional": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "peer": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "peer": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "peer": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "optional": true + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "peer": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "peer": true + }, + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "peer": true + }, + "duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "optional": true, + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.417", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.417.tgz", + "integrity": "sha512-8rY8HdCxuSVY8wku3i/eDac4g1b4cSbruzocenrqBlzqruAZYHjQCHIjC66dLR9DXhEHTojsC4EjhZ8KmzwXqA==", + "dev": true, + "peer": true + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "peer": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "devOptional": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, + "requires": { + "once": "^1.4.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "optional": true + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "optional": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "peer": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "devOptional": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "devOptional": true + }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "optional": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "optional": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "optional": true + }, + "espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "optional": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "devOptional": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "optional": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "optional": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "optional": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "peer": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "peer": true + }, + "expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "peer": true, + "requires": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "optional": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "peer": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "optional": true + }, + "fast-text-encoding": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", + "optional": true + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "peer": true, + "requires": { + "bser": "2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "peer": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "peer": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "firebase-admin": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.9.0.tgz", + "integrity": "sha512-My7qrInVZFmImX8aTulrp9kgY6d88Wn+ie8UIXKzZ3SJqQQhDwFT7Q3pgQXK9RfdsUtcxJJ3rCK7MWBm4GGtuw==", + "requires": { + "@fastify/busboy": "^1.2.1", + "@firebase/database-compat": "^0.3.4", + "@firebase/database-types": "^0.10.4", + "@google-cloud/firestore": "^6.6.0", + "@google-cloud/storage": "^6.9.5", + "@types/node": ">=12.12.47", + "jsonwebtoken": "^9.0.0", + "jwks-rsa": "^3.0.1", + "node-forge": "^1.3.1", + "uuid": "^9.0.0" + } + }, + "firebase-functions": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.4.0.tgz", + "integrity": "sha512-Vdkr9/y/UKQez//cPm2Iu/9CeayqQ2tQF6o3KXozDDBokK9AOlAalVHImCpKo6nWptT/ncZ8djJFk5cR8l+E+A==", + "requires": { + "@types/cors": "^2.8.5", + "@types/express": "4.17.3", + "cors": "^2.8.5", + "express": "^4.17.1", + "node-fetch": "^2.6.7", + "protobufjs": "^7.2.2" + } + }, + "firebase-functions-test": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/firebase-functions-test/-/firebase-functions-test-3.1.0.tgz", + "integrity": "sha512-yfm9ToguShxmRXb7TINN88zE2bM9gsBbs7vMWVKJAxGcl/n1f/U0sT5k2yho676QIcSqXVSjCONU8W4cUEL+Sw==", + "dev": true, + "requires": { + "@types/lodash": "^4.14.104", + "lodash": "^4.17.5", + "ts-deepmerge": "^2.0.1" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "devOptional": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true, + "peer": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "optional": true + }, + "gaxios": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.0.tgz", + "integrity": "sha512-aezGIjb+/VfsJtIcHGcBSerNEDdfdHeMros+RbYbGpmonKWQCOVOes0LVZhn1lDtIgq55qq0HaxymIoae3Fl/A==", + "optional": true, + "requires": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + } + }, + "gcp-metadata": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.2.0.tgz", + "integrity": "sha512-aFhhvvNycky2QyhG+dcfEdHBF0FRbYcf39s6WNHUDysKSrbJ5vuFbjydxBcmewtXeV248GP8dWT3ByPNxsyHCw==", + "optional": true, + "requires": { + "gaxios": "^5.0.0", + "json-bigint": "^1.0.0" + } + }, + "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==", + "dev": true, + "peer": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "devOptional": true + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "peer": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "peer": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "devOptional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "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, + "peer": true + }, + "google-auth-library": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.8.0.tgz", + "integrity": "sha512-0iJn7IDqObDG5Tu9Tn2WemmJ31ksEa96IyK0J0OZCpTh6CrC6FrattwKX87h3qKVuprCJpdOGKc1Xi8V0kMh8Q==", + "optional": true, + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^5.0.0", + "gcp-metadata": "^5.2.0", + "gtoken": "^6.1.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-gax": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.0.tgz", + "integrity": "sha512-2fyb61vWxUonHiArRNJQmE4tx5oY1ni8VPo08fzII409vDSCWG7apDX4qNOQ2GXXT82gLBn3d3P1Dydh7pWjyw==", + "optional": true, + "requires": { + "@grpc/grpc-js": "~1.8.0", + "@grpc/proto-loader": "^0.7.0", + "@types/long": "^4.0.0", + "@types/rimraf": "^3.0.2", + "abort-controller": "^3.0.0", + "duplexify": "^4.0.0", + "fast-text-encoding": "^1.0.3", + "google-auth-library": "^8.0.2", + "is-stream-ended": "^0.1.4", + "node-fetch": "^2.6.1", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^1.0.0", + "protobufjs": "7.2.3", + "protobufjs-cli": "1.1.1", + "retry-request": "^5.0.0" + } + }, + "google-p12-pem": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", + "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", + "optional": true, + "requires": { + "node-forge": "^1.3.1" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "devOptional": true + }, + "gtoken": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", + "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", + "optional": true, + "requires": { + "gaxios": "^5.0.1", + "google-p12-pem": "^4.0.0", + "jws": "^4.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "peer": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "optional": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "peer": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "peer": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "peer": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "devOptional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "peer": true + }, + "is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dev": true, + "peer": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "devOptional": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "peer": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "peer": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "devOptional": true + }, + "is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", + "optional": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "peer": true + }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "peer": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "peer": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "peer": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + } + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "peer": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", + "import-local": "^3.0.2", + "jest-cli": "^29.5.0" + } + }, + "jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "peer": true, + "requires": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "dev": true, + "peer": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "dev": true, + "peer": true, + "requires": { + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + } + }, + "jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "peer": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + } + }, + "jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "peer": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "dev": true, + "peer": true, + "requires": { + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" + } + }, + "jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "dev": true, + "peer": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + } + }, + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "peer": true + }, + "jest-haste-map": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "dev": true, + "peer": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "dev": true, + "peer": true, + "requires": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + } + }, + "jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + } + }, + "jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "dev": true, + "peer": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "peer": true, + "requires": {} + }, + "jest-regex-util": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", + "dev": true, + "peer": true + }, + "jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "dev": true, + "peer": true, + "requires": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" + } + }, + "jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + } + }, + "jest-runtime": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "peer": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "peer": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "dev": true, + "peer": true, + "requires": { + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "peer": true + } + } + }, + "jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "peer": true, + "requires": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "peer": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "optional": true, + "requires": { + "xmlcreate": "^2.0.4" + } + }, + "jsdoc": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", + "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "optional": true, + "requires": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "peer": true + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "optional": true, + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "peer": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true + }, + "jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "requires": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "dependencies": { + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "optional": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jwks-rsa": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz", + "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==", + "requires": { + "@types/express": "^4.17.14", + "@types/jsonwebtoken": "^9.0.0", + "debug": "^4.3.4", + "jose": "^4.10.4", + "limiter": "^1.1.5", + "lru-memoizer": "^2.1.4" + }, + "dependencies": { + "@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "optional": true, + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "peer": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "peer": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "optional": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "peer": true + }, + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "optional": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "peer": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "optional": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "optional": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lru-memoizer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", + "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "requires": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "~4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", + "requires": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + } + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "peer": true, + "requires": { + "semver": "^6.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "peer": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "optional": true, + "requires": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "optional": true + } + } + }, + "markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "optional": true, + "requires": {} + }, + "marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "optional": true + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "optional": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "peer": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "peer": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "optional": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "peer": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "optional": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "peer": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "peer": true + }, + "node-releases": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "dev": true, + "peer": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "peer": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "peer": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "optional": true + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "peer": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "optional": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "devOptional": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "peer": true, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "peer": true, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "peer": true + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "peer": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "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==", + "dev": true, + "peer": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "devOptional": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "peer": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "peer": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true, + "peer": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "peer": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "peer": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "peer": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "optional": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "peer": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "peer": true + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "peer": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "proto3-json-serializer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", + "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", + "optional": true, + "requires": { + "protobufjs": "^7.0.0" + } + }, + "protobufjs": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz", + "integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "dependencies": { + "long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + } + } + }, + "protobufjs-cli": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", + "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", + "optional": true, + "requires": { + "chalk": "^4.0.0", + "escodegen": "^1.13.0", + "espree": "^9.0.0", + "estraverse": "^5.1.0", + "glob": "^8.0.0", + "jsdoc": "^4.0.0", + "minimist": "^1.2.0", + "semver": "^7.1.2", + "tmp": "^0.2.1", + "uglify-js": "^3.7.7" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "optional": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "optional": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "optional": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "pure-rand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", + "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "dev": true, + "peer": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true, + "peer": true + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "optional": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "devOptional": true + }, + "requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "optional": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "peer": true, + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "peer": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "peer": true + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "peer": true + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "optional": true + }, + "retry-request": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", + "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", + "optional": true, + "requires": { + "debug": "^4.1.1", + "extend": "^3.0.2" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + } + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "peer": true + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "peer": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "peer": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "peer": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "peer": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "peer": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "peer": true + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "peer": true, + "requires": { + "escape-string-regexp": "^2.0.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "optional": true, + "requires": { + "stubs": "^3.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "optional": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "optional": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "peer": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "devOptional": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "peer": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "peer": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "devOptional": true + }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", + "optional": true + }, + "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==", + "devOptional": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "peer": true + }, + "teeny-request": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", + "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "optional": true, + "requires": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^9.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "peer": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-decoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", + "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "optional": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "peer": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "peer": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "peer": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "ts-deepmerge": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-2.0.7.tgz", + "integrity": "sha512-3phiGcxPSSR47RBubQxPoZ+pqXsEsozLo4G4AlSrsMKTFg9TA3l+3he5BqpUi9wiuDbaHWXH/amlzQ49uEdXtg==", + "dev": true + }, + "tslib": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz", + "integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "optional": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "peer": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "peer": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "optional": true + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true + }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "optional": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "peer": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "optional": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + }, + "v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "dependencies": { + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "peer": true + } + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "peer": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "peer": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "optional": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "devOptional": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "peer": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "optional": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "devOptional": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "devOptional": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "devOptional": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "devOptional": true + } + } +} diff --git a/scripts/webframeworks-deploy-tests/functions/package.json b/scripts/webframeworks-deploy-tests/functions/package.json new file mode 100644 index 00000000000..392196b9844 --- /dev/null +++ b/scripts/webframeworks-deploy-tests/functions/package.json @@ -0,0 +1,23 @@ +{ + "name": "functions", + "description": "Cloud Functions for Firebase", + "scripts": { + "serve": "firebase emulators:start --only functions", + "shell": "firebase functions:shell", + "start": "npm run shell", + "deploy": "firebase deploy --only functions", + "logs": "firebase functions:log" + }, + "engines": { + "node": "18" + }, + "main": "index.js", + "dependencies": { + "firebase-admin": "^11.8.0", + "firebase-functions": "^4.3.1" + }, + "devDependencies": { + "firebase-functions-test": "^3.1.0" + }, + "private": true +} diff --git a/scripts/webframeworks-deploy-tests/nextjs/next.config.js b/scripts/webframeworks-deploy-tests/nextjs/next.config.js index f4da21ee399..021cc97aa01 100644 --- a/scripts/webframeworks-deploy-tests/nextjs/next.config.js +++ b/scripts/webframeworks-deploy-tests/nextjs/next.config.js @@ -10,6 +10,28 @@ const nextConfig = { locales: ['en', 'fr'], defaultLocale: 'en', }, + rewrites: () => [{ + source: '/about', + destination: '/', + },], + redirects: () => [{ + source: '/about', + destination: '/', + permanent: true, + },], + headers: () => [{ + source: '/about', + headers: [ + { + key: 'x-custom-header', + value: 'my custom header value', + }, + { + key: 'x-another-custom-header', + value: 'my other custom header value', + }, + ], + },], } module.exports = nextConfig diff --git a/scripts/webframeworks-deploy-tests/run.sh b/scripts/webframeworks-deploy-tests/run.sh index f678a53053e..da7d13db0d2 100755 --- a/scripts/webframeworks-deploy-tests/run.sh +++ b/scripts/webframeworks-deploy-tests/run.sh @@ -6,11 +6,8 @@ set -e # Immediately exit on failure source scripts/set-default-credentials.sh -(cd scripts/webframeworks-deploy-tests/nextjs; -npm ci; -cd ../angular; -npm ci; -cd ..; -FIREBASE_CLI_EXPERIMENTS=webframeworks,pintags firebase emulators:exec "cd ../..; mocha scripts/webframeworks-deploy-tests/tests.ts" --project $FBTOOLS_TARGET_PROJECT --debug > firebase-emulators.log || \ -(cat firebase-emulators.log && exit 1); -cat firebase-emulators.log) +npm ci --prefix scripts/webframeworks-deploy-tests/nextjs +npm ci --prefix scripts/webframeworks-deploy-tests/angular +npm ci --prefix scripts/webframeworks-deploy-tests/functions + +FIREBASE_CLI_EXPERIMENTS=webframeworks,pintags firebase emulators:exec "mocha scripts/webframeworks-deploy-tests/tests.ts" --config scripts/webframeworks-deploy-tests/firebase.json --project demo-123 --debug diff --git a/scripts/webframeworks-deploy-tests/tests.ts b/scripts/webframeworks-deploy-tests/tests.ts index d223bb36ad6..58cc1bf3fc5 100644 --- a/scripts/webframeworks-deploy-tests/tests.ts +++ b/scripts/webframeworks-deploy-tests/tests.ts @@ -16,7 +16,7 @@ const NEXT_BASE_PATH: NextConfig["basePath"] = "base"; const ANGULAR_BASE_PATH = ""; const I18N_BASE = ""; const DEFAULT_LANG = "en"; -const LOG_FILE = "scripts/webframeworks-deploy-tests/firebase-emulators.log"; +const LOG_FILE = "firebase-debug.log"; const NEXT_SOURCE = `${__dirname}/nextjs`; async function getFilesListFromDir(dir: string): Promise { @@ -48,6 +48,149 @@ describe("webframeworks", function (this) { // This is not an empty block. }); + describe("build", () => { + it("should have the correct effective firebase.json", () => { + const result = readFileSync(LOG_FILE).toString(); + const effectiveFirebaseJSON = result + .split("[web frameworks] effective firebase.json: ") + .at(-1) + ?.split(new RegExp(`(\\[\\S+\\] )?\\[${new Date().getFullYear()}`))[0] + ?.trim(); + expect(effectiveFirebaseJSON && JSON.parse(effectiveFirebaseJSON), "firebase.json").to.eql({ + hosting: [ + { + target: "nextjs", + source: "nextjs", + frameworksBackend: { + maxInstances: 1, + region: "asia-east1", + }, + rewrites: [ + { + destination: "/base", + source: "/base/about", + }, + { + source: "/base/**", + function: { + functionId: "ssrdemonextjs", + region: "asia-east1", + pinTag: true, + }, + }, + { + function: { + functionId: "helloWorld", + }, + source: "helloWorld", + }, + ], + site: "demo-nextjs", + redirects: [ + { + destination: "/base/", + source: "/base/en/about", + type: 308, + }, + { + destination: "/base", + source: "/base/about", + type: 308, + }, + ], + headers: [ + { + headers: [ + { + key: "x-custom-header", + value: "my custom header value", + }, + { + key: "x-another-custom-header", + value: "my other custom header value", + }, + ], + source: "/base/about", + }, + { + source: "/base/app/api/static", + headers: [ + { + key: "content-type", + value: "application/json", + }, + { + key: "custom-header", + value: "custom-value", + }, + { + key: "x-next-cache-tags", + value: "/app/api/static/route", + }, + ], + }, + ], + cleanUrls: true, + trailingSlash: false, + i18n: { + root: "/", + }, + public: ".firebase/demo-nextjs/hosting", + webFramework: "next_ssr", + }, + { + target: "angular", + source: "angular", + frameworksBackend: { + maxInstances: 1, + region: "europe-west1", + }, + rewrites: [ + { + function: { + functionId: "helloWorld", + }, + source: "helloWorld", + }, + { + source: "/**", + function: { + functionId: "ssrdemoangular", + region: "europe-west1", + pinTag: true, + }, + }, + ], + site: "demo-angular", + redirects: [], + headers: [], + cleanUrls: true, + i18n: { + root: "/", + }, + public: ".firebase/demo-angular/hosting", + webFramework: "angular_ssr", + }, + ], + functions: [ + { + codebase: "default", + ignore: ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log"], + source: "functions", + }, + { + codebase: "firebase-frameworks-demo-nextjs", + source: ".firebase/demo-nextjs/functions", + }, + { + codebase: "firebase-frameworks-demo-angular", + source: ".firebase/demo-angular/functions", + }, + ], + }); + }); + }); + describe("next.js", () => { describe("app directory", () => { it("should have working SSG", async () => { diff --git a/src/frameworks/angular/index.ts b/src/frameworks/angular/index.ts index 5c4dd4bdeec..c0c0e4d2831 100644 --- a/src/frameworks/angular/index.ts +++ b/src/frameworks/angular/index.ts @@ -65,10 +65,13 @@ export async function init(setup: any, config: any) { } export async function build(dir: string, configuration: string): Promise { - const { targets, serverTarget, serveOptimizedImages, locales, baseHref } = await getBuildConfig( - dir, - configuration - ); + const { + targets, + serverTarget, + serveOptimizedImages, + locales, + baseHref: baseUrl, + } = await getBuildConfig(dir, configuration); await warnIfCustomBuildScript(dir, name, DEFAULT_BUILD_SCRIPT); for (const target of targets) { // TODO there is a bug here. Spawn for now. @@ -86,12 +89,12 @@ export async function build(dir: string, configuration: string): Promise req.sendStatus(404);\n`; - rewriteSource = posix.join(baseUrl, "__image__"); + rewriteSource = posix.join(baseHref, "__image__"); } - return { bootstrapScript, packageJson, baseUrl, dotEnv, rewriteSource }; + return { bootstrapScript, packageJson, dotEnv, rewriteSource }; } diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index 21be5fa8c73..42509442101 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -53,6 +53,7 @@ import { logWarning } from "../utils"; import { ensureTargeted } from "../functions/ensureTargeted"; import { isDeepStrictEqual } from "util"; import { resolveProjectPath } from "../projectPath"; +import { logger } from "../logger"; export { WebFrameworks }; @@ -255,7 +256,7 @@ export async function prepareFrameworks( getValidBuildTargets = GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = WebFrameworks[framework]; - console.log( + logger.info( `\n${frameworksCallToAction(SupportLevelWarnings[support](name), docsUrl, " ")}\n` ); @@ -267,6 +268,10 @@ export async function prepareFrameworks( (await shouldUseDevModeHandle(frameworksBuildTarget, getProjectPath())); let codegenFunctionsDirectory: Framework["ɵcodegenFunctionsDirectory"]; + let baseUrl = ""; + const rewrites = []; + const redirects = []; + const headers = []; const devModeHandle = useDevModeHandle && @@ -287,18 +292,15 @@ export async function prepareFrameworks( [firebaseDefaults, frameworksBuildTarget], frameworksBuildTarget ); - const { - wantsBackend = false, - rewrites = [], - redirects = [], - headers = [], - trailingSlash, - i18n = false, - }: BuildResult = buildResult || {}; - - config.rewrites.push(...rewrites); - config.redirects.push(...redirects); - config.headers.push(...headers); + const { wantsBackend = false, trailingSlash, i18n = false }: BuildResult = buildResult || {}; + + if (buildResult) { + baseUrl = buildResult.baseUrl ?? baseUrl; + if (buildResult.headers) headers.push(...buildResult.headers); + if (buildResult.rewrites) rewrites.push(...buildResult.rewrites); + if (buildResult.redirects) redirects.push(...buildResult.redirects); + } + config.trailingSlash ??= trailingSlash; if (i18n) config.i18n ??= { root: I18N_ROOT }; @@ -374,22 +376,27 @@ export async function prepareFrameworks( packageJson, bootstrapScript, frameworksEntry = framework, - baseUrl = "", dotEnv = {}, - rewriteSource = posix.join(baseUrl, "**"), + rewriteSource, } = await codegenFunctionsDirectory(getProjectPath(), functionsDist, frameworksBuildTarget); - config.rewrites = [ - { - source: rewriteSource, - function: { - functionId, - region: ssrRegion, - pinTag: experiments.isEnabled("pintags"), - }, + const rewrite = { + source: rewriteSource || posix.join(baseUrl, "**"), + function: { + functionId, + region: ssrRegion, + pinTag: experiments.isEnabled("pintags"), }, - ...config.rewrites, - ]; + }; + + // If the rewriteSource is overridden, we're talking a very specific rewrite. E.g, Image Optimization + // in this case, we should ensure that it's the first priority—otherwise defer to the push/unshift + // logic based off the baseUrl + if (rewriteSource) { + config.rewrites.unshift(rewrite); + } else { + rewrites.push(rewrite); + } // Set the framework entry in the env variables to handle generation of the functions.yaml process.env.__FIREBASE_FRAMEWORKS_ENTRY__ = frameworksEntry; @@ -527,13 +534,20 @@ ${ } } + const ourConfigShouldComeFirst = !["", "/"].includes(baseUrl); + const operation = ourConfigShouldComeFirst ? "unshift" : "push"; + + config.rewrites[operation](...rewrites); + config.redirects[operation](...redirects); + config.headers[operation](...headers); + if (firebaseDefaults) { const encodedDefaults = Buffer.from(JSON.stringify(firebaseDefaults)).toString("base64url"); const expires = new Date(new Date().getTime() + 60_000_000_000); const sameSite = "Strict"; const path = `/`; config.headers.push({ - source: "**/*.[jt]s", + source: posix.join(baseUrl, "**", "*.[jt]s"), headers: [ { key: "Set-Cookie", @@ -543,10 +557,11 @@ ${ }); } } - if (process.env.DEBUG) { - console.log("Effective firebase.json:"); - console.log(JSON.stringify(configs, undefined, 2)); - } + + logger.debug( + "[web frameworks] effective firebase.json: ", + JSON.stringify({ hosting: configs, functions: options.config.get("functions") }, undefined, 2) + ); // Clean up memos/caches BUILD_MEMO.clear(); diff --git a/src/frameworks/interfaces.ts b/src/frameworks/interfaces.ts index d8f79a23d7c..06cf7062aaf 100644 --- a/src/frameworks/interfaces.ts +++ b/src/frameworks/interfaces.ts @@ -32,9 +32,14 @@ export interface BuildResult { wantsBackend?: boolean; trailingSlash?: boolean; i18n?: boolean; + baseUrl?: string; } -export type RequestHandler = (req: IncomingMessage, res: ServerResponse, next: () => void) => void; +export type RequestHandler = ( + req: IncomingMessage, + res: ServerResponse, + next: () => void +) => void | Promise; export type FrameworksOptions = HostingOptions & Options & { @@ -77,7 +82,6 @@ export interface Framework { bootstrapScript?: string; packageJson: any; frameworksEntry?: string; - baseUrl?: string; dotEnv?: Record; rewriteSource?: string; }>; diff --git a/src/frameworks/next/index.ts b/src/frameworks/next/index.ts index 1a2c9360c61..e64ae4865d1 100644 --- a/src/frameworks/next/index.ts +++ b/src/frameworks/next/index.ts @@ -67,6 +67,7 @@ import { APP_PATHS_MANIFEST, } from "./constants"; import { getAllSiteDomains } from "../../hosting/api"; +import { logger } from "../../logger"; const DEFAULT_BUILD_SCRIPT = ["next build"]; const PUBLIC_DIR = "public"; @@ -118,7 +119,7 @@ export async function build(dir: string): Promise { }); const reasonsForBackend = new Set(); - const { distDir, trailingSlash, basePath } = await getConfig(dir); + const { distDir, trailingSlash, basePath: baseUrl } = await getConfig(dir); if (await isUsingMiddleware(join(dir, distDir), false)) { reasonsForBackend.add("middleware"); @@ -198,7 +199,7 @@ export async function build(dir: string): Promise { const headersFromMetaFiles = await getHeadersFromMetaFiles( dir, distDir, - basePath, + baseUrl, appPathRoutesManifest ); headers.push(...headersFromMetaFiles); @@ -261,19 +262,24 @@ export async function build(dir: string): Promise { const wantsBackend = reasonsForBackend.size > 0; if (wantsBackend) { - const numberOfReasonsToList = process.env.DEBUG ? Infinity : DEFAULT_NUMBER_OF_REASONS_TO_LIST; - console.log("Building a Cloud Function to run this application. This is needed due to:"); - for (const reason of Array.from(reasonsForBackend).slice(0, numberOfReasonsToList)) { - console.log(` • ${reason}`); + logger.info("Building a Cloud Function to run this application. This is needed due to:"); + for (const reason of Array.from(reasonsForBackend).slice( + 0, + DEFAULT_NUMBER_OF_REASONS_TO_LIST + )) { + logger.info(` • ${reason}`); } - if (reasonsForBackend.size > numberOfReasonsToList) { - console.log( + for (const reason of Array.from(reasonsForBackend).slice(DEFAULT_NUMBER_OF_REASONS_TO_LIST)) { + logger.debug(` • ${reason}`); + } + if (reasonsForBackend.size > DEFAULT_NUMBER_OF_REASONS_TO_LIST && !process.env.DEBUG) { + logger.info( ` • and ${ - reasonsForBackend.size - numberOfReasonsToList + reasonsForBackend.size - DEFAULT_NUMBER_OF_REASONS_TO_LIST } other reasons, use --debug to see more` ); } - console.log(""); + logger.info(""); } const i18n = !!nextjsI18n; @@ -285,6 +291,7 @@ export async function build(dir: string): Promise { rewrites, trailingSlash, i18n, + baseUrl, }; } @@ -391,14 +398,13 @@ export async function ɵcodegenPublicDirectory( await Promise.all( Object.entries(routesToCopy).map(async ([path, route]) => { if (route.initialRevalidateSeconds) { - if (process.env.DEBUG) console.log(`skipping ${path} due to revalidate`); + logger.debug(`skipping ${path} due to revalidate`); return; } if (pathsUsingsFeaturesNotSupportedByHosting.some((it) => path.match(it))) { - if (process.env.DEBUG) - console.log( - `skipping ${path} due to it matching an unsupported rewrite/redirect/header or middlware` - ); + logger.debug( + `skipping ${path} due to it matching an unsupported rewrite/redirect/header or middlware` + ); return; } const appPathRoute = @@ -415,8 +421,7 @@ export async function ɵcodegenPublicDirectory( matchingI18nDomain.locales.includes(locale); if (!includeOnThisDomain) { - if (process.env.DEBUG) - console.log(`skipping ${path} since it is for a locale not deployed on this domain`); + logger.debug(`skipping ${path} since it is for a locale not deployed on this domain`); return; } @@ -472,7 +477,7 @@ const BUNDLE_NEXT_CONFIG_TIMEOUT = 10_000; * Create a directory for SSR content. */ export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: string) { - const { distDir, basePath } = await getConfig(sourceDir); + const { distDir } = await getConfig(sourceDir); const packageJson = await readJSON(join(sourceDir, "package.json")); // Bundle their next.config.js with esbuild via NPX, pinned version was having troubles on m1 // macs and older Node versions; either way, we should avoid taking on any deps in firebase-tools @@ -545,7 +550,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string, destDir: st await mkdirp(join(destDir, distDir)); await copy(join(sourceDir, distDir), join(destDir, distDir)); - return { packageJson, frameworksEntry: "next.js", basePath }; + return { packageJson, frameworksEntry: "next.js" }; } /** diff --git a/src/frameworks/nuxt/index.ts b/src/frameworks/nuxt/index.ts index a5871f1fb52..8b79667f9c1 100644 --- a/src/frameworks/nuxt/index.ts +++ b/src/frameworks/nuxt/index.ts @@ -44,7 +44,7 @@ export async function build(cwd: string) { const cli = getNodeModuleBin("nuxt", cwd); const { ssr: wantsBackend, - app: { baseURL }, + app: { baseURL: baseUrl }, } = await getConfig(cwd); const command = wantsBackend ? ["build"] : ["generate"]; const build = spawnSync(cli, command, { @@ -57,11 +57,11 @@ export async function build(cwd: string) { ? [] : [ { - source: posix.join(baseURL, "**"), - destination: posix.join(baseURL, "200.html"), + source: posix.join(baseUrl, "**"), + destination: posix.join(baseUrl, "200.html"), }, ]; - return { wantsBackend, rewrites }; + return { wantsBackend, rewrites, baseUrl }; } export async function ɵcodegenPublicDirectory(root: string, dest: string) { @@ -82,11 +82,7 @@ export async function ɵcodegenFunctionsDirectory(sourceDir: string) { packageJson.dependencies ||= {}; packageJson.dependencies["nitro-output"] = `file:${serverDir}`; - const { - app: { baseURL: baseUrl }, - } = await getConfig(sourceDir); - - return { packageJson, frameworksEntry: "nitro", baseUrl }; + return { packageJson, frameworksEntry: "nitro" }; } export async function getDevModeHandle(cwd: string) { diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index acf58c336cf..4c139fc9ab3 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -18,7 +18,7 @@ import { NPM_COMMAND_TIMEOUT_MILLIES, VALID_LOCALE_FORMATS, } from "./constants"; -import { BUILD_TARGET_PURPOSE } from "./interfaces"; +import { BUILD_TARGET_PURPOSE, RequestHandler } from "./interfaces"; // Use "true &&"" to keep typescript from compiling this file and rewriting // the import statement into a require @@ -63,7 +63,21 @@ export async function warnIfCustomBuildScript( } } -type RequestHandler = (req: IncomingMessage, res: ServerResponse) => Promise; +function proxyResponse(original: ServerResponse, next: () => void) { + return (response: IncomingMessage | ServerResponse) => { + const { statusCode, statusMessage } = response; + if (!statusCode) { + original.end(); + return; + } + if (statusCode === 404) { + return next(); + } + const headers = "getHeaders" in response ? response.getHeaders() : response.headers; + original.writeHead(statusCode, statusMessage, headers); + response.pipe(original); + }; +} export function simpleProxy(hostOrRequestHandler: string | RequestHandler) { const agent = new Agent({ keepAlive: true }); @@ -100,8 +114,12 @@ export function simpleProxy(hostOrRequestHandler: string | RequestHandler) { }; const req = httpRequest(opts, (response) => { const { statusCode, statusMessage, headers } = response; - originalRes.writeHead(statusCode!, statusMessage, headers); - response.pipe(originalRes); + if (statusCode === 404) { + next(); + } else { + originalRes.writeHead(statusCode!, statusMessage, headers); + response.pipe(originalRes); + } }); originalReq.pipe(req); req.on("error", (err) => { @@ -109,7 +127,9 @@ export function simpleProxy(hostOrRequestHandler: string | RequestHandler) { originalRes.end(); }); } else { - await hostOrRequestHandler(originalReq, originalRes); + await Promise.resolve(hostOrRequestHandler(originalReq, originalRes, next)); + const proxiedRes = new ServerResponse(originalReq); + proxyResponse(originalRes, next)(proxiedRes); } }; } From 76f159a23372112900e9e9b39631a6a48a71d4d5 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Thu, 1 Jun 2023 22:34:48 +0000 Subject: [PATCH 046/320] 12.3.0 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 860dec4d957..fb524af2aa3 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.2.1", + "version": "12.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.2.1", + "version": "12.3.0", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index 79b3482916a..510bff324d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.2.1", + "version": "12.3.0", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From ac467a17f294183e276f4acc8c205fcb6c5792ee Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Thu, 1 Jun 2023 22:35:01 +0000 Subject: [PATCH 047/320] [firebase-release] Removed change log and reset repo after 12.3.0 release --- CHANGELOG.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6822691b7c4..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +0,0 @@ -- Fix a bug preventing web framework's dev-mode from working out-of-box with Firebase Authentication. (#5894) -- Address additional cases where we were attempting to deploy a framework's development bundle (#5895) -- NextJS rewrites should be prefixed with the basePath defined in next.config.js (#5923) -- Web Frameworks emulators will again respect existing Cloud Functions rewrites (#5923) -- Web Frameworks rewrites/redirects/headers will only prepend those in firebase.json if there's a baseUrl (#5923) -- Fixes issue where Authentication emulator creates a user if empty email and empty password is provided. (#5639) -- Improve error message raised when `--import` flag directory does not exist. (#5851) -- Switch `ext:dev:init` to default 'billingRequired' to true in `extension.yaml` -- Remove `LOCATION` param from the `extensions.yaml` template for `ext:dev:init` -- Support Astro hybrid rendering (#5898) From e0d0b1b6cb9e1f7355d88cbd31546496dcbc9e0e Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Fri, 2 Jun 2023 09:47:50 -0700 Subject: [PATCH 048/320] Allow secrets to be set before deploying functions (#5918) * Allow secrets to be set before deploying functions * Changelog * Remove debug prints; run formatter --------- Co-authored-by: Daniel Lee --- CHANGELOG.md | 1 + src/commands/functions-secrets-access.ts | 2 ++ src/commands/functions-secrets-destroy.ts | 1 + src/commands/functions-secrets-get.ts | 2 ++ src/commands/functions-secrets-prune.ts | 5 +++-- src/commands/functions-secrets-set.ts | 14 ++++++++++++++ src/functions/secrets.ts | 10 ++++++++++ 7 files changed, 33 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..b09f81abf14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- firebase functions:secrets:\* ensure the secretmanager API is enabled (#5918) diff --git a/src/commands/functions-secrets-access.ts b/src/commands/functions-secrets-access.ts index e82849d01ca..fde041e6b89 100644 --- a/src/commands/functions-secrets-access.ts +++ b/src/commands/functions-secrets-access.ts @@ -3,11 +3,13 @@ import { logger } from "../logger"; import { Options } from "../options"; import { needProjectId } from "../projectUtils"; import { accessSecretVersion } from "../gcp/secretManager"; +import * as secrets from "../functions/secrets"; export const command = new Command("functions:secrets:access [@version]") .description( "Access secret value given secret and its version. Defaults to accessing the latest version." ) + .before(secrets.ensureApi) .action(async (key: string, options: Options) => { const projectId = needProjectId(options); let [name, version] = key.split("@"); diff --git a/src/commands/functions-secrets-destroy.ts b/src/commands/functions-secrets-destroy.ts index d9fadc6af6c..2314620abef 100644 --- a/src/commands/functions-secrets-destroy.ts +++ b/src/commands/functions-secrets-destroy.ts @@ -17,6 +17,7 @@ import * as args from "../deploy/functions/args"; export const command = new Command("functions:secrets:destroy [@version]") .description("Destroy a secret. Defaults to destroying the latest version.") .withForce("Destroys a secret without confirmation.") + .before(secrets.ensureApi) .action(async (key: string, options: Options) => { const projectId = needProjectId(options); const projectNumber = await needProjectNumber(options); diff --git a/src/commands/functions-secrets-get.ts b/src/commands/functions-secrets-get.ts index 48e52403b10..1115db2c086 100644 --- a/src/commands/functions-secrets-get.ts +++ b/src/commands/functions-secrets-get.ts @@ -6,9 +6,11 @@ import { Options } from "../options"; import { needProjectId } from "../projectUtils"; import { listSecretVersions } from "../gcp/secretManager"; import { requirePermissions } from "../requirePermissions"; +import * as secrets from "../functions/secrets"; export const command = new Command("functions:secrets:get ") .description("Get metadata for secret and its versions") + .before(secrets.ensureApi) .before(requirePermissions, ["secretmanager.secrets.get"]) .action(async (key: string, options: Options) => { const projectId = needProjectId(options); diff --git a/src/commands/functions-secrets-prune.ts b/src/commands/functions-secrets-prune.ts index f4ec99db7dc..50fbd9d0f0e 100644 --- a/src/commands/functions-secrets-prune.ts +++ b/src/commands/functions-secrets-prune.ts @@ -3,7 +3,7 @@ import * as backend from "../deploy/functions/backend"; import { Command } from "../command"; import { Options } from "../options"; import { needProjectId, needProjectNumber } from "../projectUtils"; -import { pruneSecrets } from "../functions/secrets"; +import * as secrets from "../functions/secrets"; import { requirePermissions } from "../requirePermissions"; import { isFirebaseManaged } from "../deploymentTool"; import { logBullet, logSuccess } from "../utils"; @@ -13,6 +13,7 @@ import { destroySecretVersion } from "../gcp/secretManager"; export const command = new Command("functions:secrets:prune") .withForce("Destroys unused secrets without prompt") .description("Destroys unused secrets") + .before(secrets.ensureApi) .before(requirePermissions, [ "cloudfunctions.functions.list", "secretmanager.secrets.list", @@ -30,7 +31,7 @@ export const command = new Command("functions:secrets:prune") .allEndpoints(haveBackend) .filter((e) => isFirebaseManaged(e.labels || [])); - const pruned = await pruneSecrets({ projectNumber, projectId }, haveEndpoints); + const pruned = await secrets.pruneSecrets({ projectNumber, projectId }, haveEndpoints); if (pruned.length === 0) { logBullet("All secrets are in use. Nothing to prune today."); diff --git a/src/commands/functions-secrets-set.ts b/src/commands/functions-secrets-set.ts index d8608968f3b..c3a42ebf7ab 100644 --- a/src/commands/functions-secrets-set.ts +++ b/src/commands/functions-secrets-set.ts @@ -3,6 +3,7 @@ import * as fs from "fs"; import * as clc from "colorette"; +import { logger } from "../logger"; import { ensureValidKey, ensureSecret } from "../functions/secrets"; import { Command } from "../command"; import { requirePermissions } from "../requirePermissions"; @@ -14,10 +15,12 @@ import { addVersion, toSecretVersionResourceName } from "../gcp/secretManager"; import * as secrets from "../functions/secrets"; import * as backend from "../deploy/functions/backend"; import * as args from "../deploy/functions/args"; +import { check } from "../ensureApiEnabled"; export const command = new Command("functions:secrets:set ") .description("Create or update a secret for use in Cloud Functions for Firebase.") .withForce("Automatically updates functions to use the new secret.") + .before(secrets.ensureApi) .before(requirePermissions, [ "secretmanager.secrets.create", "secretmanager.secrets.get", @@ -60,6 +63,17 @@ export const command = new Command("functions:secrets:set ") return; } + const functionsEnabled = await check( + projectId, + "cloudfunctions.googleapis.com", + "functions", + /* silent= */ true + ); + if (!functionsEnabled) { + logger.debug("Customer set secrets before enabling functions. Exiting"); + return; + } + const haveBackend = await backend.existingBackend({ projectId } as args.Context); const endpointsToUpdate = backend .allEndpoints(haveBackend) diff --git a/src/functions/secrets.ts b/src/functions/secrets.ts index f2cf45e5e4d..98df34e9852 100644 --- a/src/functions/secrets.ts +++ b/src/functions/secrets.ts @@ -2,6 +2,7 @@ import * as utils from "../utils"; import * as poller from "../operation-poller"; import * as gcf from "../gcp/cloudfunctions"; import * as backend from "../deploy/functions/backend"; +import * as ensureApiEnabled from "../ensureApiEnabled"; import { createSecret, destroySecretVersion, @@ -22,6 +23,7 @@ import { validateKey } from "./env"; import { logger } from "../logger"; import { functionsOrigin } from "../api"; import { assertExhaustive } from "../functional"; +import { needProjectId } from "../projectUtils"; const FIREBASE_MANAGED = "firebase-managed"; @@ -52,6 +54,14 @@ function toUpperSnakeCase(key: string): string { .toUpperCase(); } +/** + * Utility used in the "before" command annotation to enable the API. + */ +export function ensureApi(options: any): Promise { + const projectId = needProjectId(options); + return ensureApiEnabled.ensure(projectId, "secretmanager.googleapis.com", "runtimeconfig", true); +} + /** * Validate and transform keys to match the convention recommended by Firebase. */ From 858695fd07ee0b4d858ba3bf62617de252c28377 Mon Sep 17 00:00:00 2001 From: christhompsongoogle <106194718+christhompsongoogle@users.noreply.github.com> Date: Fri, 2 Jun 2023 18:32:38 -0700 Subject: [PATCH 049/320] Export on exit typing (#5932) * Add some more explicit typing to exportOnExit See a similar example here: https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgCoHcD2AhTmA2yA3gFDLJwBcyARnvhHCANxm3V0GMskC+JoSLEQoA8iAi4CxNlU4MmrfjACuIBGGCYQyABYR8+TAAoADnChwAttXGT6ASmS2JUwqXIJtAZy4A6IwBzYwAic0sbEOQAamQAKQBlUQA5P28wKFBA4BgATzMLawcHVnJw6z84ZABeZHh8bwhS5C8QXwYAzGCQq0wAExzgCD7KKNjElLSMrJz88qti5qgIMBUoHXmlElb05DAsN2oMHHoa4ioMlQgAGnZ6xt5WHf8g0OXV9eHRmPik1PTMiBsnljPpDJhkMZ9icCMUSkA --- src/emulator/commandUtils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/emulator/commandUtils.ts b/src/emulator/commandUtils.ts index 712288d7e2a..888f1973609 100644 --- a/src/emulator/commandUtils.ts +++ b/src/emulator/commandUtils.ts @@ -190,7 +190,10 @@ export function parseInspectionPort(options: any): number { * export data the first time they start developing on a clean project. * @param options */ -export function setExportOnExitOptions(options: any) { +export function setExportOnExitOptions(options: { + exportOnExit: boolean | string; + import?: string; +}): void { if (options.exportOnExit || typeof options.exportOnExit === "string") { // note that options.exportOnExit may be a bool when used as a flag without a [dir] argument: // --import ./data --export-on-exit From afcbcdd284585ea6523fb672d9cd110ce594543b Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Tue, 6 Jun 2023 10:16:31 -0700 Subject: [PATCH 050/320] Framework composer (#5839) Internal code to dockerize projects. --- src/commands/index.ts | 2 + .../internaltesting-frameworks-compose.ts | 21 ++ src/frameworks/compose/discover/index.ts | 28 +++ src/frameworks/compose/driver/docker.ts | 209 ++++++++++++++++++ src/frameworks/compose/driver/hooks.ts | 35 +++ src/frameworks/compose/driver/index.ts | 19 ++ src/frameworks/compose/driver/local.ts | 46 ++++ src/frameworks/compose/index.ts | 38 ++++ src/frameworks/compose/interfaces.ts | 59 +++++ .../frameworks/compose/engine/docker.spec.ts | 92 ++++++++ .../frameworks/compose/engine/hooks.spec.ts | 42 ++++ 11 files changed, 591 insertions(+) create mode 100644 src/commands/internaltesting-frameworks-compose.ts create mode 100644 src/frameworks/compose/discover/index.ts create mode 100644 src/frameworks/compose/driver/docker.ts create mode 100644 src/frameworks/compose/driver/hooks.ts create mode 100644 src/frameworks/compose/driver/index.ts create mode 100644 src/frameworks/compose/driver/local.ts create mode 100644 src/frameworks/compose/index.ts create mode 100644 src/frameworks/compose/interfaces.ts create mode 100644 src/test/frameworks/compose/engine/docker.spec.ts create mode 100644 src/test/frameworks/compose/engine/hooks.spec.ts diff --git a/src/commands/index.ts b/src/commands/index.ts index b67a6a20657..8d7de5c2362 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -143,6 +143,8 @@ export function load(client: any): any { client.init = loadCommand("init"); if (experiments.isEnabled("internaltesting")) { client.internaltesting = {}; + client.internaltesting.frameworks = {}; + client.internaltesting.frameworks.compose = loadCommand("internaltesting-frameworks-compose"); client.internaltesting.functions = {}; client.internaltesting.functions.discover = loadCommand("internaltesting-functions-discover"); } diff --git a/src/commands/internaltesting-frameworks-compose.ts b/src/commands/internaltesting-frameworks-compose.ts new file mode 100644 index 00000000000..ee85ec27d8a --- /dev/null +++ b/src/commands/internaltesting-frameworks-compose.ts @@ -0,0 +1,21 @@ +import { Command } from "../command"; +import { Options } from "../options"; +import { logger } from "../logger"; +import { Mode, SUPPORTED_MODES } from "../frameworks/compose/driver"; +import { compose } from "../frameworks/compose"; +import { FirebaseError } from "../error"; + +export const command = new Command("internaltesting:frameworks:compose") + .option("-m, --mode ", "Composer mode (local or docker)", "local") + .description("compose framework in current directory") + .action((options: Options) => { + const mode = options.mode as string; + if (!(SUPPORTED_MODES as unknown as string[]).includes(mode)) { + throw new FirebaseError( + `Unsupported mode ${mode}. Supported modes are [${SUPPORTED_MODES.join(", ")}]` + ); + } + const bundle = compose(mode as Mode); + logger.info(JSON.stringify(bundle, null, 2)); + return {}; + }); diff --git a/src/frameworks/compose/discover/index.ts b/src/frameworks/compose/discover/index.ts new file mode 100644 index 00000000000..8d3c8542ab3 --- /dev/null +++ b/src/frameworks/compose/discover/index.ts @@ -0,0 +1,28 @@ +import { AppSpec } from "../interfaces"; + +/** + * Discover framework in the given project directory + */ +export function discover(): AppSpec { + return { + baseImage: "us-docker.pkg.dev/firestack-build/test/run:latest", + environmentVariables: { + NODE_ENV: "PRODUCTION", + }, + installCommand: "npm install", + buildCommand: "npm run build", + startCommand: "npm run start", + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + afterInstall: (b) => { + console.log("HOOK: AFTER INSTALL"); + return { ...b, version: "v1alpha", notes: "afterInstall" }; + }, + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + afterBuild(b) { + console.log("HOOK: AFTER BUILD"); + return { ...b, version: "v1alpha", notes: "afterBuild" }; + }, + }; +} diff --git a/src/frameworks/compose/driver/docker.ts b/src/frameworks/compose/driver/docker.ts new file mode 100644 index 00000000000..70d9d4344b9 --- /dev/null +++ b/src/frameworks/compose/driver/docker.ts @@ -0,0 +1,209 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as spawn from "cross-spawn"; + +import { AppBundle, AppSpec, Driver, Hook } from "../interfaces"; +import { BUNDLE_PATH, genHookScript } from "./hooks"; + +const ADAPTER_SCRIPTS_PATH = "./.firebase/adapters" as const; + +const DOCKER_STAGE_INSTALL = "installer" as const; +const DOCKER_STAGE_BUILD = "builder" as const; + +export class DockerfileBuilder { + private dockerfile = ""; + private lastStage = ""; + + from(image: string, name?: string): DockerfileBuilder { + this.dockerfile += `FROM ${image}`; + if (name) { + this.dockerfile += ` AS ${name}`; + this.lastStage = name; + } + this.dockerfile += "\n"; + return this; + } + + fromLastStage(name: string): DockerfileBuilder { + return this.from(this.lastStage, name); + } + + /** + * Last `from` but does not update the lastStage. + */ + tempFrom(image: string, name?: string): DockerfileBuilder { + this.dockerfile += `FROM ${image}`; + if (name) { + this.dockerfile += ` AS ${name}`; + } + this.dockerfile += "\n"; + return this; + } + + workdir(dir: string): DockerfileBuilder { + this.dockerfile += `WORKDIR ${dir}\n`; + return this; + } + + copyForFirebase(src: string, dest: string, from?: string): DockerfileBuilder { + if (from) { + this.dockerfile += `COPY --chown=firebase:firebase --from=${from} ${src} ${dest}\n`; + } else { + this.dockerfile += `COPY --chown=firebase:firebase ${src} ${dest}\n`; + } + return this; + } + + copyFrom(src: string, dest: string, from: string) { + this.dockerfile += `COPY --from=${from} ${src} ${dest}\n`; + return this; + } + + run(cmd: string, mount?: string): DockerfileBuilder { + if (mount) { + this.dockerfile += `RUN --mount=${mount} ${cmd}\n`; + } else { + this.dockerfile += `RUN ${cmd}\n`; + } + return this; + } + + env(key: string, value: string): DockerfileBuilder { + this.dockerfile += `ENV ${key}="${value}"\n`; + return this; + } + + envs(envs: Record): DockerfileBuilder { + for (const [key, value] of Object.entries(envs)) { + this.env(key, value); + } + return this; + } + + cmd(cmds: string[]): DockerfileBuilder { + this.dockerfile += `CMD [${cmds.map((c) => `"${c}"`).join(", ")}]\n`; + return this; + } + + user(user: string): DockerfileBuilder { + this.dockerfile += `USER ${user}\n`; + return this; + } + + toString(): string { + return this.dockerfile; + } +} + +export class DockerDriver implements Driver { + private dockerfileBuilder; + + constructor(readonly spec: AppSpec) { + this.dockerfileBuilder = new DockerfileBuilder(); + this.dockerfileBuilder.from(spec.baseImage, "base").user("firebase"); + } + + private execDockerPush(args: string[]) { + console.log(`executing docker build: ${args.join(" ")}`); + return spawn.sync("docker", ["push", ...args], { + stdio: [/* stdin= */ "pipe", /* stdout= */ "inherit", /* stderr= */ "inherit"], + }); + } + + private execDockerBuild(args: string[], contextDir: string) { + console.log(`executing docker build: ${args.join(" ")} ${contextDir}`); + console.log(this.dockerfileBuilder.toString()); + return spawn.sync("docker", ["buildx", "build", ...args, "-f", "-", contextDir], { + env: { ...process.env, ...this.spec.environmentVariables }, + input: this.dockerfileBuilder.toString(), + stdio: [/* stdin= */ "pipe", /* stdout= */ "inherit", /* stderr= */ "inherit"], + }); + } + + private buildStage(stage: string, contextDir: string, tag?: string): void { + console.log(`Building stage: ${stage}`); + const args = ["--target", stage]; + if (tag) { + args.push("--tag", tag); + } + const ret = this.execDockerBuild(args, contextDir); + if (ret.error || ret.status !== 0) { + throw new Error(`Failed to execute stage ${stage}: error=${ret.error} status=${ret.status}`); + } + } + + private exportBundle(stage: string, contextDir: string): AppBundle { + const exportStage = `${stage}-export`; + this.dockerfileBuilder + .tempFrom("scratch", exportStage) + .copyFrom(BUNDLE_PATH, "/bundle.json", stage); + const ret = this.execDockerBuild( + ["--target", exportStage, "--output", ".firebase/.output"], + contextDir + ); + if (ret.error || ret.status !== 0) { + throw new Error(`Failed to export bundle ${stage}: error=${ret.error} status=${ret.status}`); + } + return JSON.parse(fs.readFileSync("./.firebase/.output/bundle.json", "utf8")) as AppBundle; + } + + install(): void { + this.dockerfileBuilder + .fromLastStage(DOCKER_STAGE_INSTALL) + .workdir("/home/firebase/app") + .envs(this.spec.environmentVariables || {}) + .copyForFirebase("package.json", ".") + .run(this.spec.installCommand); + this.buildStage(DOCKER_STAGE_INSTALL, "."); + } + + build(): void { + this.dockerfileBuilder + .fromLastStage(DOCKER_STAGE_BUILD) + .copyForFirebase(".", ".") + .run(this.spec.buildCommand); + this.buildStage(DOCKER_STAGE_BUILD, "."); + } + + export(bundle: AppBundle): void { + const startCmd = bundle.server?.start.cmd; + if (startCmd) { + const exportStage = "exporter"; + this.dockerfileBuilder + .from(this.spec.baseImage, exportStage) + .workdir("/home/firebase/app") + .copyForFirebase("/home/firebase/app", ".", DOCKER_STAGE_BUILD) + .cmd(startCmd); + const imageName = `us-docker.pkg.dev/${process.env.PROJECT_ID}/test/demo-nodappe`; + this.buildStage(exportStage, ".", imageName); + const ret = this.execDockerPush([imageName]); + if (ret.error || ret.status !== 0) { + throw new Error( + `Failed to push image ${imageName}: error=${ret.error} status=${ret.status}` + ); + } + } + } + + execHook(bundle: AppBundle, hook: Hook): AppBundle { + // Prepare hook execution by writing the node script locally + const hookScript = `hook-${Date.now()}.js`; + const hookScriptSrc = genHookScript(bundle, hook); + + if (!fs.existsSync(ADAPTER_SCRIPTS_PATH)) { + fs.mkdirSync(ADAPTER_SCRIPTS_PATH, { recursive: true }); + } + fs.writeFileSync(path.join(ADAPTER_SCRIPTS_PATH, hookScript), hookScriptSrc); + + // Execute the hook inside the docker sandbox + const hookStage = path.basename(hookScript, ".js"); + this.dockerfileBuilder + .fromLastStage(hookStage) + .run( + `NODE_PATH=./node_modules node /framework/adapters/${hookScript}`, + `source=${ADAPTER_SCRIPTS_PATH},target=/framework/adapters` + ); + this.buildStage(hookStage, "."); + return this.exportBundle(hookStage, "."); + } +} diff --git a/src/frameworks/compose/driver/hooks.ts b/src/frameworks/compose/driver/hooks.ts new file mode 100644 index 00000000000..e4fa8aa7182 --- /dev/null +++ b/src/frameworks/compose/driver/hooks.ts @@ -0,0 +1,35 @@ +import { AppBundle, Hook } from "../interfaces"; + +export const BUNDLE_PATH = "/home/firebase/app/.firebase/.output/bundle.json" as const; + +/** + * Generate a script that wraps the given hook to output the resulting AppBundle + * to a well-known path. + */ +export function genHookScript(bundle: AppBundle, hook: Hook): string { + let hookSrc = hook.toString().trimLeft(); + // Hook must be IIFE-able. All hook functions are IFFE-able without modification + // except for function defined inside an object in the following form: + // + // { + // afterInstall(b) { + // ... + // . } + // } + // + // We detect and transform function defined in this form by prefixing "functions " + if (!hookSrc.startsWith("(") && !hookSrc.startsWith("function ")) { + hookSrc = `function ${hookSrc}`; + } + return ` +const fs = require("node:fs"); +const path = require("node:path"); + +const bundleDir = path.dirname("${BUNDLE_PATH}"); +if (!fs.existsSync(bundleDir)) { + fs.mkdirSync(bundleDir, { recursive: true }); +} +const bundle = (${hookSrc})(${JSON.stringify(bundle)}); +fs.writeFileSync("${BUNDLE_PATH}", JSON.stringify(bundle)); +`; +} diff --git a/src/frameworks/compose/driver/index.ts b/src/frameworks/compose/driver/index.ts new file mode 100644 index 00000000000..8adc6480708 --- /dev/null +++ b/src/frameworks/compose/driver/index.ts @@ -0,0 +1,19 @@ +import { AppSpec, Driver } from "../interfaces"; +import { LocalDriver } from "./local"; +import { DockerDriver } from "./docker"; + +export const SUPPORTED_MODES = ["local", "docker"] as const; +export type Mode = (typeof SUPPORTED_MODES)[number]; + +/** + * Returns the driver that provides the execution context for the composer. + */ +export function getDriver(mode: Mode, app: AppSpec): Driver { + if (mode === "local") { + return new LocalDriver(app); + } else if (mode === "docker") { + return new DockerDriver(app); + } + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new Error(`Unsupported mode ${mode}`); +} diff --git a/src/frameworks/compose/driver/local.ts b/src/frameworks/compose/driver/local.ts new file mode 100644 index 00000000000..da23187bf58 --- /dev/null +++ b/src/frameworks/compose/driver/local.ts @@ -0,0 +1,46 @@ +import * as fs from "node:fs"; +import * as spawn from "cross-spawn"; + +import { AppBundle, AppSpec, Hook, Driver } from "../interfaces"; +import { BUNDLE_PATH, genHookScript } from "./hooks"; + +export class LocalDriver implements Driver { + constructor(readonly spec: AppSpec) {} + + private execCmd(cmd: string, args: string[]) { + const ret = spawn.sync(cmd, args, { + env: { ...process.env, ...this.spec.environmentVariables }, + stdio: [/* stdin= */ "pipe", /* stdout= */ "inherit", /* stderr= */ "inherit"], + }); + if (ret.error) { + throw ret.error; + } + } + + install(): void { + const [cmd, ...args] = this.spec.installCommand.split(" "); + this.execCmd(cmd, args); + } + + build(): void { + const [cmd, ...args] = this.spec.buildCommand.split(" "); + this.execCmd(cmd, args); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + export(bundle: AppBundle): void { + // no-op + } + + execHook(bundle: AppBundle, hook: Hook): AppBundle { + const script = genHookScript(bundle, hook); + this.execCmd("node", ["-e", script]); + if (!fs.existsSync(BUNDLE_PATH)) { + console.warn(`Expected hook to generate app bundle at ${BUNDLE_PATH} but got nothing.`); + console.warn("Returning original bundle."); + return bundle; + } + const newBundle = JSON.parse(fs.readFileSync(BUNDLE_PATH, "utf8")); + return newBundle as AppBundle; + } +} diff --git a/src/frameworks/compose/index.ts b/src/frameworks/compose/index.ts new file mode 100644 index 00000000000..24e45490be1 --- /dev/null +++ b/src/frameworks/compose/index.ts @@ -0,0 +1,38 @@ +import { AppBundle } from "./interfaces"; +import { getDriver, Mode } from "./driver"; +import { discover } from "./discover"; + +/** + * Run composer in the specified execution context. + */ +export function compose(mode: Mode): AppBundle { + let bundle: AppBundle = { version: "v1alpha" }; + const spec = discover(); + const driver = getDriver(mode, spec); + + if (spec.startCommand) { + bundle.server = { + start: { + cmd: spec.startCommand.split(" "), + }, + }; + } + + driver.install(); + if (spec.afterInstall) { + bundle = driver.execHook(bundle, spec.afterInstall); + } + + driver.build(); + if (spec.afterBuild) { + bundle = driver.execHook(bundle, spec.afterBuild); + } + + if (bundle.server) { + // Export container + driver.export(bundle); + } + + // TODO: Update stack config + return bundle; +} diff --git a/src/frameworks/compose/interfaces.ts b/src/frameworks/compose/interfaces.ts new file mode 100644 index 00000000000..db3caee4898 --- /dev/null +++ b/src/frameworks/compose/interfaces.ts @@ -0,0 +1,59 @@ +export interface AppBundle { + version: "v1alpha"; + server?: ServerConfig; +} + +interface ServerConfig { + start: StartConfig; + concurrency?: number; + cpu?: number; + memory?: "256MiB" | "512MiB" | "1GiB" | "2GiB" | "4GiB" | "8GiB" | "16GiB" | string; + timeoutSeconds?: number; + minInstances?: number; + maxInstances?: number; +} + +interface StartConfig { + // Path to local source directory. Defaults to .bundle/server. + dir?: string; + // Command to start the server (e.g. ["npm", "run", "start"]). + cmd: string[]; + // Runtime required to command execution. + runtime?: "nodejs18" | string; +} + +export interface AppSpec { + baseImage: string; + packageManagerInstallCommand?: string; + environmentVariables?: Record; + installCommand: string; + buildCommand: string; + startCommand: string; + + afterInstall?: (b: AppBundle) => AppBundle; + afterBuild?: (b: AppBundle) => AppBundle; +} + +export type Hook = (b: AppBundle) => AppBundle; + +export class Driver { + constructor(readonly spec: AppSpec) {} + + install(): void { + throw new Error("install() not implemented"); + } + + build(): void { + throw new Error("build() not implemented"); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + export(bundle: AppBundle): void { + throw new Error("export() not implemented"); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + execHook(bundle: AppBundle, hook: Hook): AppBundle { + throw new Error("execHook() not implemented"); + } +} diff --git a/src/test/frameworks/compose/engine/docker.spec.ts b/src/test/frameworks/compose/engine/docker.spec.ts new file mode 100644 index 00000000000..f5591bd805d --- /dev/null +++ b/src/test/frameworks/compose/engine/docker.spec.ts @@ -0,0 +1,92 @@ +import { expect } from "chai"; +import { DockerfileBuilder } from "../../../../frameworks/compose/driver/docker"; + +describe("DockerfileBuilder", () => { + describe("from", () => { + it("should add a FROM instruction to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.from("node:18", "base"); + expect(builder.toString()).to.equal("FROM node:18 AS base\n"); + }); + + it("should add a FROM instruction to the Dockerfile without a name", () => { + const builder = new DockerfileBuilder(); + builder.from("node:18"); + expect(builder.toString()).to.equal("FROM node:18\n"); + }); + }); + + describe("fromLastStage", () => { + it("should add a FROM instruction to the Dockerfile using the last stage name", () => { + const builder = new DockerfileBuilder(); + builder.from("node:18", "base").fromLastStage("test"); + expect(builder.toString()).to.equal("FROM node:18 AS base\nFROM base AS test\n"); + }); + }); + + describe("tempFrom", () => { + it("should add a FROM instruction without updating last stage", () => { + const builder = new DockerfileBuilder(); + builder.from("node:18", "base").tempFrom("node:20", "temp").fromLastStage("test"); + expect(builder.toString()).to.equal( + "FROM node:18 AS base\nFROM node:20 AS temp\nFROM base AS test\n" + ); + }); + }); + + describe("workdir", () => { + it("should add a WORKDIR instruction to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.workdir("/app"); + expect(builder.toString()).to.equal("WORKDIR /app\n"); + }); + }); + + describe("run", () => { + it("should add a RUN instruction to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.run('echo "test"'); + expect(builder.toString()).to.equal('RUN echo "test"\n'); + }); + }); + + describe("cmd", () => { + it("should add a CMD instruction to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.cmd(["node", "index.js"]); + expect(builder.toString()).to.equal('CMD ["node", "index.js"]\n'); + }); + }); + + describe("copyForFirebase", () => { + it("should add a COPY instruction to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.copyForFirebase("src", "dest"); + expect(builder.toString()).to.equal("COPY --chown=firebase:firebase src dest\n"); + }); + }); + + describe("copyFrom", () => { + it("should add a COPY instruction to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.copyFrom("src", "dest", "stage"); + expect(builder.toString()).to.equal("COPY --from=stage src dest\n"); + }); + }); + + describe("env", () => { + it("should add an ENV instruction to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.env("NODE_ENV", "production"); + expect(builder.toString()).to.equal('ENV NODE_ENV="production"\n'); + }); + }); + + describe("envs", () => { + it("should add multiple ENV instructions to the Dockerfile", () => { + const builder = new DockerfileBuilder(); + builder.envs({ NODE_ENV: "production", PORT: "8080" }); + expect(builder.toString()).to.equal('ENV NODE_ENV="production"\nENV PORT="8080"\n'); + }); + }); +}); diff --git a/src/test/frameworks/compose/engine/hooks.spec.ts b/src/test/frameworks/compose/engine/hooks.spec.ts new file mode 100644 index 00000000000..c759972293b --- /dev/null +++ b/src/test/frameworks/compose/engine/hooks.spec.ts @@ -0,0 +1,42 @@ +import { expect } from "chai"; +import { genHookScript } from "../../../../frameworks/compose/driver/hooks"; +import { AppBundle } from "../../../../frameworks/compose/interfaces"; + +describe("genHookScript", () => { + const BUNDLE: AppBundle = { + version: "v1alpha", + }; + + it("generates executable script from anonymous functions", () => { + const hookFn = (b: AppBundle): AppBundle => { + return b; + }; + const expectedSnippet = `const bundle = ((b) => { + return b; + })({"version":"v1alpha"});`; + expect(genHookScript(BUNDLE, hookFn)).to.include(expectedSnippet); + }); + + it("generates executable script from a named function", () => { + function hookFn(b: AppBundle): AppBundle { + return b; + } + const expectedSnippet = `const bundle = (function hookFn(b) { + return b; + })({"version":"v1alpha"});`; + expect(genHookScript(BUNDLE, hookFn)).to.include(expectedSnippet); + }); + + it("generates executable script from an object method", () => { + const a = { + hookFn(b: AppBundle) { + return b; + }, + }; + const expectedSnippet = `const bundle = (function hookFn(b) { + return b; + })({"version":"v1alpha"});`; + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(genHookScript(BUNDLE, a.hookFn)).to.include(expectedSnippet); + }); +}); From 6d9047fd4ee910f1370467bd11eb2fdc76a5b01c Mon Sep 17 00:00:00 2001 From: blidd-google <112491344+blidd-google@users.noreply.github.com> Date: Tue, 6 Jun 2023 13:48:12 -0400 Subject: [PATCH 051/320] Delete and re-create v2 function on Cloud Run API quota exhaustion (#5719) * delete function on cloud run quota exhaustion and re-create * add changelog * change retry code name * custom specified retry codes override defaults * allow to disable retries in executor --- CHANGELOG.md | 2 + src/deploy/functions/release/executor.ts | 38 ++++++--- src/deploy/functions/release/fabricator.ts | 77 ++++++++++++------- .../deploy/functions/release/executor.spec.ts | 11 +++ .../functions/release/fabricator.spec.ts | 14 ++++ 5 files changed, 105 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b09f81abf14..318f8cf8184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,3 @@ +- Delete and re-create v2 function on Cloud Run API quota exhaustion (#5719). +- Address additional cases where we were attempting to deploy a framework's development bundle (#5895) - firebase functions:secrets:\* ensure the secretmanager API is enabled (#5918) diff --git a/src/deploy/functions/release/executor.ts b/src/deploy/functions/release/executor.ts index 271bba5f869..471004fa40d 100644 --- a/src/deploy/functions/release/executor.ts +++ b/src/deploy/functions/release/executor.ts @@ -5,15 +5,32 @@ import { ThrottlerOptions } from "../../../throttler/throttler"; * An Executor runs lambdas (which may be async). */ export interface Executor { - run(func: () => Promise): Promise; + run(func: () => Promise, opts?: RunOptions): Promise; +} + +export interface RunOptions { + retryCodes?: number[]; } interface Operation { func: () => any; + retryCodes: number[]; result?: any; error?: any; } +export const DEFAULT_RETRY_CODES = [429, 409, 503]; + +function parseErrorCode(err: any): number { + return ( + err.status || + err.code || + err.context?.response?.statusCode || + err.original?.code || + err.original?.context?.response?.statusCode + ); +} + async function handler(op: Operation): Promise { try { op.result = await op.func(); @@ -24,15 +41,11 @@ async function handler(op: Operation): Promise { // errors. This can be a raw error with the correct HTTP code, a raw // error with the HTTP code stashed where GCP puts it, or a FirebaseError // wrapping either of the previous two cases. - const code = - err.status || - err.code || - err.context?.response?.statusCode || - err.original?.code || - err.original?.context?.response?.statusCode; - if (code === 429 || code === 409 || code === 503) { + const code = parseErrorCode(err); + if (op.retryCodes.includes(code)) { throw err; } + err.code = code; op.error = err; } return; @@ -49,8 +62,13 @@ export class QueueExecutor implements Executor { this.queue = new Queue({ ...options, handler }); } - async run(func: () => Promise): Promise { - const op: Operation = { func }; + async run(func: () => Promise, opts?: RunOptions): Promise { + const retryCodes = opts?.retryCodes || DEFAULT_RETRY_CODES; + + const op: Operation = { + func, + retryCodes, + }; await this.queue.run(op); if (op.error) { throw op.error; diff --git a/src/deploy/functions/release/fabricator.ts b/src/deploy/functions/release/fabricator.ts index 1ca388f9f43..7f282fa9724 100644 --- a/src/deploy/functions/release/fabricator.ts +++ b/src/deploy/functions/release/fabricator.ts @@ -1,6 +1,6 @@ import * as clc from "colorette"; -import { Executor } from "./executor"; +import { DEFAULT_RETRY_CODES, Executor } from "./executor"; import { FirebaseError } from "../../../error"; import { SourceTokenScraper } from "./sourceTokenScraper"; import { Timer } from "./timer"; @@ -50,6 +50,8 @@ const eventarcPollerOptions: Omit { - const op: { name: string } = await gcfV2.createFunction(apiFunction); - return await poller.pollOperation({ - ...gcfV2PollerOptions, - pollerName: `create-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, - operationResourceName: op.name, + let resultFunction: gcfV2.OutputCloudFunction | null = null; + while (!resultFunction) { + resultFunction = await this.functionExecutor + .run(async () => { + const op: { name: string } = await gcfV2.createFunction(apiFunction); + return await poller.pollOperation({ + ...gcfV2PollerOptions, + pollerName: `create-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, + operationResourceName: op.name, + }); + }) + .catch(async (err: any) => { + // If the createFunction call returns RPC error code RESOURCE_EXHAUSTED (8), + // we have exhausted the underlying Cloud Run API quota. To retry, we need to + // first delete the GCF function resource, then call createFunction again. + if (err.code === CLOUD_RUN_RESOURCE_EXHAUSTED_CODE) { + // we have to delete the broken function before we can re-create it + await this.deleteV2Function(endpoint); + return null; + } else { + logger.error((err as Error).message); + throw new reporter.DeploymentError(endpoint, "create", err); + } }); - }) - .catch(rethrowAs(endpoint, "create")); + } endpoint.uri = resultFunction.serviceConfig?.uri; const serviceName = resultFunction.serviceConfig?.service; @@ -463,14 +480,17 @@ export class Fabricator { } const resultFunction = await this.functionExecutor - .run(async () => { - const op: { name: string } = await gcfV2.updateFunction(apiFunction); - return await poller.pollOperation({ - ...gcfV2PollerOptions, - pollerName: `update-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, - operationResourceName: op.name, - }); - }) + .run( + async () => { + const op: { name: string } = await gcfV2.updateFunction(apiFunction); + return await poller.pollOperation({ + ...gcfV2PollerOptions, + pollerName: `update-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, + operationResourceName: op.name, + }); + }, + { retryCodes: [...DEFAULT_RETRY_CODES, CLOUD_RUN_RESOURCE_EXHAUSTED_CODE] } + ) .catch(rethrowAs(endpoint, "update")); endpoint.uri = resultFunction.serviceConfig?.uri; @@ -523,15 +543,18 @@ export class Fabricator { async deleteV2Function(endpoint: backend.Endpoint): Promise { const fnName = backend.functionName(endpoint); await this.functionExecutor - .run(async () => { - const op: { name: string } = await gcfV2.deleteFunction(fnName); - const pollerOptions = { - ...gcfV2PollerOptions, - pollerName: `delete-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, - operationResourceName: op.name, - }; - await poller.pollOperation(pollerOptions); - }) + .run( + async () => { + const op: { name: string } = await gcfV2.deleteFunction(fnName); + const pollerOptions = { + ...gcfV2PollerOptions, + pollerName: `delete-${endpoint.codebase}-${endpoint.region}-${endpoint.id}`, + operationResourceName: op.name, + }; + await poller.pollOperation(pollerOptions); + }, + { retryCodes: [...DEFAULT_RETRY_CODES, CLOUD_RUN_RESOURCE_EXHAUSTED_CODE] } + ) .catch(rethrowAs(endpoint, "delete")); } diff --git a/src/test/deploy/functions/release/executor.spec.ts b/src/test/deploy/functions/release/executor.spec.ts index f819b3b3d59..547eda2e4a9 100644 --- a/src/test/deploy/functions/release/executor.spec.ts +++ b/src/test/deploy/functions/release/executor.spec.ts @@ -45,5 +45,16 @@ describe("Executor", () => { }; await expect(exec.run(handler)).to.eventually.be.rejectedWith("Retryable"); }); + + it("retries on custom specified retry codes", async () => { + const handler = (): Promise => { + const err = new Error("Retryable"); + (err as any).code = 8; + throw err; + }; + await expect( + exec.run(handler, { retryCodes: [...executor.DEFAULT_RETRY_CODES, 8] }) + ).to.eventually.be.rejectedWith("Retryable"); + }); }); }); diff --git a/src/test/deploy/functions/release/fabricator.spec.ts b/src/test/deploy/functions/release/fabricator.spec.ts index f5a26a0633e..99b8e5e0517 100644 --- a/src/test/deploy/functions/release/fabricator.spec.ts +++ b/src/test/deploy/functions/release/fabricator.spec.ts @@ -612,6 +612,20 @@ describe("Fabricator", () => { await expect(fab.createV2Function(ep)).to.be.rejectedWith(reporter.DeploymentError, "create"); }); + it("deletes broken function and retries on cloud run quota exhaustion", async () => { + gcfv2.createFunction.onFirstCall().rejects({ message: "Cloud Run quota exhausted", code: 8 }); + gcfv2.createFunction.resolves({ name: "op", done: false }); + + gcfv2.deleteFunction.resolves({ name: "op", done: false }); + poller.pollOperation.resolves({ name: "op" }); + + const ep = endpoint({ httpsTrigger: {} }, { platform: "gcfv2" }); + await fab.createV2Function(ep); + + expect(gcfv2.createFunction).to.have.been.calledTwice; + expect(gcfv2.deleteFunction).to.have.been.called; + }); + it("throws on set invoker failure", async () => { gcfv2.createFunction.resolves({ name: "op", done: false }); poller.pollOperation.resolves({ serviceConfig: { service: "service" } }); From 78fb757a939c7e7a4de1eb88740b39d19a2a5e1a Mon Sep 17 00:00:00 2001 From: joehan Date: Tue, 6 Jun 2023 14:06:38 -0700 Subject: [PATCH 052/320] Fix merge conflict (#5939) --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 318f8cf8184..4a19e4466dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,2 @@ - Delete and re-create v2 function on Cloud Run API quota exhaustion (#5719). -- Address additional cases where we were attempting to deploy a framework's development bundle (#5895) - firebase functions:secrets:\* ensure the secretmanager API is enabled (#5918) From 06d5f78750ad6959773772c3ddaa9a45d3221d83 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 6 Jun 2023 21:18:32 +0000 Subject: [PATCH 053/320] 12.3.1 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index fb524af2aa3..44dd1fcdf1a 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.3.0", + "version": "12.3.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.3.0", + "version": "12.3.1", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index 510bff324d0..11f013e1d22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.3.0", + "version": "12.3.1", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From dc08ce421417fdec7a3ce01099967fe7d1dd62ff Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 6 Jun 2023 21:18:48 +0000 Subject: [PATCH 054/320] [firebase-release] Removed change log and reset repo after 12.3.1 release --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a19e4466dd..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +0,0 @@ -- Delete and re-create v2 function on Cloud Run API quota exhaustion (#5719). -- firebase functions:secrets:\* ensure the secretmanager API is enabled (#5918) From ab0455404b73de5183e3478c4838c4100adbb763 Mon Sep 17 00:00:00 2001 From: aalej Date: Thu, 8 Jun 2023 02:12:56 +0800 Subject: [PATCH 055/320] Update experiments:describe description (#5868) * Update experiments:describe description * Update src/commands/experiments-describe.ts --------- Co-authored-by: joehan --- src/commands/experiments-describe.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/experiments-describe.ts b/src/commands/experiments-describe.ts index 079bc08ed4a..f46b7195688 100644 --- a/src/commands/experiments-describe.ts +++ b/src/commands/experiments-describe.ts @@ -7,7 +7,7 @@ import { logger } from "../logger"; import { last } from "../utils"; export const command = new Command("experiments:describe ") - .description("enable an experiment on this machine") + .description("describe what an experiment does when enabled") .action((experiment: string) => { if (!experiments.isValidExperiment(experiment)) { let message = `Cannot find experiment ${bold(experiment)}`; From 628aa7525e025f7872f57cc1a823fe7c9e9bab57 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Fri, 9 Jun 2023 12:34:59 -0700 Subject: [PATCH 056/320] VSCode Plugin initial implementation (#5930) --- .eslintrc.js | 2 + firebase-vscode/.eslintrc.json | 24 + firebase-vscode/.gitignore | 4 + firebase-vscode/.prettierrc.js | 3 + firebase-vscode/.vscode/extensions.json | 7 + firebase-vscode/.vscode/launch.json | 34 + firebase-vscode/.vscode/settings.json | 11 + firebase-vscode/.vscode/tasks.json | 20 + firebase-vscode/.vscodeignore | 18 + firebase-vscode/CHANGELOG.md | 9 + firebase-vscode/LICENSE | 21 + firebase-vscode/README.md | 64 + firebase-vscode/common/firebaserc.ts | 2 + firebase-vscode/common/messaging/broker.ts | 87 + firebase-vscode/common/messaging/protocol.ts | 122 + firebase-vscode/common/messaging/types.d.ts | 17 + firebase-vscode/common/types.d.ts | 8 + firebase-vscode/package-lock.json | 9769 +++++++++++++++++ firebase-vscode/package.json | 115 + firebase-vscode/resources/Monicons.woff | Bin 0 -> 1932 bytes firebase-vscode/scripts/swap-pkg.js | 29 + firebase-vscode/src/cli.ts | 214 + firebase-vscode/src/extension-broker.ts | 41 + firebase-vscode/src/extension.ts | 30 + firebase-vscode/src/html-scaffold.ts | 68 + firebase-vscode/src/logger-wrapper.ts | 15 + firebase-vscode/src/options.ts | 99 + firebase-vscode/src/sidebar.ts | 65 + firebase-vscode/src/stubs/empty-class.js | 3 + firebase-vscode/src/stubs/empty-function.js | 3 + firebase-vscode/src/stubs/inquirer-stub.js | 31 + firebase-vscode/src/stubs/marked.js | 5 + firebase-vscode/src/test/runTest.ts | 23 + .../src/test/suite/extension.test.ts | 15 + firebase-vscode/src/test/suite/index.ts | 38 + firebase-vscode/src/utils.ts | 11 + firebase-vscode/src/workflow.ts | 449 + firebase-vscode/tsconfig.json | 19 + firebase-vscode/webpack.common.js | 199 + firebase-vscode/webpack.dev.js | 6 + firebase-vscode/webpack.prod.js | 7 + firebase-vscode/webviews/SidebarApp.tsx | 161 + .../webviews/components/AccountSection.scss | 20 + .../webviews/components/AccountSection.tsx | 131 + .../webviews/components/DeployPanel.tsx | 186 + .../webviews/components/ProjectSection.tsx | 79 + .../webviews/components/ui/ExternalLink.tsx | 11 + .../webviews/components/ui/Icon.scss | 21 + .../webviews/components/ui/Icon.tsx | 441 + .../webviews/components/ui/IconButton.tsx | 30 + .../webviews/components/ui/PanelSection.scss | 20 + .../webviews/components/ui/PanelSection.tsx | 42 + .../webviews/components/ui/Spacer.scss | 23 + .../webviews/components/ui/Spacer.tsx | 14 + .../webviews/components/ui/Text.scss | 94 + .../webviews/components/ui/Text.tsx | 58 + .../components/ui/popup-menu/PopupMenu.scss | 57 + .../components/ui/popup-menu/PopupMenu.tsx | 57 + .../webviews/globals/html-broker.ts | 22 + firebase-vscode/webviews/globals/index.scss | 12 + firebase-vscode/webviews/globals/tokens.scss | 8 + firebase-vscode/webviews/globals/vscode.scss | 38 + .../webviews/globals/web-logger.ts | 18 + firebase-vscode/webviews/sidebar.entry.scss | 54 + firebase-vscode/webviews/sidebar.entry.tsx | 6 + firebase-vscode/webviews/tsconfig.json | 14 + firebase-vscode/webviews/webview-types.ts | 2 + src/monospace/index.ts | 155 + src/monospace/interfaces.ts | 33 + src/options.ts | 3 + src/requireAuth.ts | 13 +- 71 files changed, 13529 insertions(+), 1 deletion(-) create mode 100644 firebase-vscode/.eslintrc.json create mode 100644 firebase-vscode/.gitignore create mode 100644 firebase-vscode/.prettierrc.js create mode 100644 firebase-vscode/.vscode/extensions.json create mode 100644 firebase-vscode/.vscode/launch.json create mode 100644 firebase-vscode/.vscode/settings.json create mode 100644 firebase-vscode/.vscode/tasks.json create mode 100644 firebase-vscode/.vscodeignore create mode 100644 firebase-vscode/CHANGELOG.md create mode 100644 firebase-vscode/LICENSE create mode 100644 firebase-vscode/README.md create mode 100644 firebase-vscode/common/firebaserc.ts create mode 100644 firebase-vscode/common/messaging/broker.ts create mode 100644 firebase-vscode/common/messaging/protocol.ts create mode 100644 firebase-vscode/common/messaging/types.d.ts create mode 100644 firebase-vscode/common/types.d.ts create mode 100644 firebase-vscode/package-lock.json create mode 100644 firebase-vscode/package.json create mode 100644 firebase-vscode/resources/Monicons.woff create mode 100644 firebase-vscode/scripts/swap-pkg.js create mode 100644 firebase-vscode/src/cli.ts create mode 100644 firebase-vscode/src/extension-broker.ts create mode 100644 firebase-vscode/src/extension.ts create mode 100644 firebase-vscode/src/html-scaffold.ts create mode 100644 firebase-vscode/src/logger-wrapper.ts create mode 100644 firebase-vscode/src/options.ts create mode 100644 firebase-vscode/src/sidebar.ts create mode 100644 firebase-vscode/src/stubs/empty-class.js create mode 100644 firebase-vscode/src/stubs/empty-function.js create mode 100644 firebase-vscode/src/stubs/inquirer-stub.js create mode 100644 firebase-vscode/src/stubs/marked.js create mode 100644 firebase-vscode/src/test/runTest.ts create mode 100644 firebase-vscode/src/test/suite/extension.test.ts create mode 100644 firebase-vscode/src/test/suite/index.ts create mode 100644 firebase-vscode/src/utils.ts create mode 100644 firebase-vscode/src/workflow.ts create mode 100644 firebase-vscode/tsconfig.json create mode 100644 firebase-vscode/webpack.common.js create mode 100644 firebase-vscode/webpack.dev.js create mode 100644 firebase-vscode/webpack.prod.js create mode 100644 firebase-vscode/webviews/SidebarApp.tsx create mode 100644 firebase-vscode/webviews/components/AccountSection.scss create mode 100644 firebase-vscode/webviews/components/AccountSection.tsx create mode 100644 firebase-vscode/webviews/components/DeployPanel.tsx create mode 100644 firebase-vscode/webviews/components/ProjectSection.tsx create mode 100644 firebase-vscode/webviews/components/ui/ExternalLink.tsx create mode 100644 firebase-vscode/webviews/components/ui/Icon.scss create mode 100644 firebase-vscode/webviews/components/ui/Icon.tsx create mode 100644 firebase-vscode/webviews/components/ui/IconButton.tsx create mode 100644 firebase-vscode/webviews/components/ui/PanelSection.scss create mode 100644 firebase-vscode/webviews/components/ui/PanelSection.tsx create mode 100644 firebase-vscode/webviews/components/ui/Spacer.scss create mode 100644 firebase-vscode/webviews/components/ui/Spacer.tsx create mode 100644 firebase-vscode/webviews/components/ui/Text.scss create mode 100644 firebase-vscode/webviews/components/ui/Text.tsx create mode 100644 firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.scss create mode 100644 firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx create mode 100644 firebase-vscode/webviews/globals/html-broker.ts create mode 100644 firebase-vscode/webviews/globals/index.scss create mode 100644 firebase-vscode/webviews/globals/tokens.scss create mode 100644 firebase-vscode/webviews/globals/vscode.scss create mode 100644 firebase-vscode/webviews/globals/web-logger.ts create mode 100644 firebase-vscode/webviews/sidebar.entry.scss create mode 100644 firebase-vscode/webviews/sidebar.entry.tsx create mode 100644 firebase-vscode/webviews/tsconfig.json create mode 100644 firebase-vscode/webviews/webview-types.ts create mode 100644 src/monospace/index.ts create mode 100644 src/monospace/interfaces.ts diff --git a/.eslintrc.js b/.eslintrc.js index 841c3a7a480..129a36e41bf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -128,5 +128,7 @@ module.exports = { "/src/frameworks/docs/**", // This file is taking a very long time to lint, 2-4m "src/emulator/auth/schema.ts", + // TODO(hsubox76): Set up a job to run eslint separately on vscode dir + "firebase-vscode/", ], }; diff --git a/firebase-vscode/.eslintrc.json b/firebase-vscode/.eslintrc.json new file mode 100644 index 00000000000..681109e79a6 --- /dev/null +++ b/firebase-vscode/.eslintrc.json @@ -0,0 +1,24 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + // "react" + ], + "rules": { + "@typescript-eslint/semi": "warn", + "curly": "warn", + "eqeqeq": "warn", + "no-throw-literal": "warn", + "semi": "off" + }, + "ignorePatterns": [ + "out", + "dist", + "**/*.d.ts" + ] +} diff --git a/firebase-vscode/.gitignore b/firebase-vscode/.gitignore new file mode 100644 index 00000000000..08ccd9d7281 --- /dev/null +++ b/firebase-vscode/.gitignore @@ -0,0 +1,4 @@ +*.vsix +dist/ +*.scss.d.ts +resources/dist diff --git a/firebase-vscode/.prettierrc.js b/firebase-vscode/.prettierrc.js new file mode 100644 index 00000000000..e83d7e4ded7 --- /dev/null +++ b/firebase-vscode/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + printWidth: 80, +}; diff --git a/firebase-vscode/.vscode/extensions.json b/firebase-vscode/.vscode/extensions.json new file mode 100644 index 00000000000..d26385a6325 --- /dev/null +++ b/firebase-vscode/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "dbaeumer.vscode-eslint" + ] +} diff --git a/firebase-vscode/.vscode/launch.json b/firebase-vscode/.vscode/launch.json new file mode 100644 index 00000000000..9ade0d5097d --- /dev/null +++ b/firebase-vscode/.vscode/launch.json @@ -0,0 +1,34 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/dist/**/*.js" + ], + "preLaunchTask": "${defaultBuildTask}" + }, + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/dist/test/suite/index" + ], + "outFiles": [ + "${workspaceFolder}/dist/test/**/*.js" + ], + "preLaunchTask": "${defaultBuildTask}" + } + ] +} diff --git a/firebase-vscode/.vscode/settings.json b/firebase-vscode/.vscode/settings.json new file mode 100644 index 00000000000..10d3a97a91d --- /dev/null +++ b/firebase-vscode/.vscode/settings.json @@ -0,0 +1,11 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "dist": false // set this to true to hide the "out" folder with the compiled JS files + }, + "search.exclude": { + "dist": true // set this to false to include "out" folder in search results + }, + // Turn off tsc task auto detection since we have the necessary tasks as npm scripts + "typescript.tsc.autoDetect": "off" +} diff --git a/firebase-vscode/.vscode/tasks.json b/firebase-vscode/.vscode/tasks.json new file mode 100644 index 00000000000..74418433df5 --- /dev/null +++ b/firebase-vscode/.vscode/tasks.json @@ -0,0 +1,20 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "watch", + "problemMatcher": ["$tsc-watch", "$ts-webpack-watch"], + "isBackground": true, + "presentation": { + "reveal": "always" + }, + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} diff --git a/firebase-vscode/.vscodeignore b/firebase-vscode/.vscodeignore new file mode 100644 index 00000000000..091caca74cd --- /dev/null +++ b/firebase-vscode/.vscodeignore @@ -0,0 +1,18 @@ +.vscode/** +.vscode-test/** +src/** +webviews/** +common/** +extension/** +public/** +.gitignore +.yarnrc +vsc-extension-quickstart.md +**/tsconfig.json +**/.eslintrc.json +**/*.map +**/*.ts +*.vsix +webpack.*.js +../ +*.zip diff --git a/firebase-vscode/CHANGELOG.md b/firebase-vscode/CHANGELOG.md new file mode 100644 index 00000000000..f73373662c2 --- /dev/null +++ b/firebase-vscode/CHANGELOG.md @@ -0,0 +1,9 @@ +# Change Log + +All notable changes to the "firebase-vscode" extension will be documented in this file. + +Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. + +## [Unreleased] + +- Initial release diff --git a/firebase-vscode/LICENSE b/firebase-vscode/LICENSE new file mode 100644 index 00000000000..3da21db2851 --- /dev/null +++ b/firebase-vscode/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 Firebase + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/firebase-vscode/README.md b/firebase-vscode/README.md new file mode 100644 index 00000000000..086212a4347 --- /dev/null +++ b/firebase-vscode/README.md @@ -0,0 +1,64 @@ +# firebase-vscode README + +This extension is in the development and exploration stage. + +## Running + +1. In order to make sure f5 launches the extension properly, first open your + VS Code session from the `firebase-vscode` subdirectory (not the `firebase-tools` directory). +2. npm i +3. f5 to run opens new window + f5 -> npm run watch defined in tasks.json + My terminal didn't have npm available but yours might + +Workaround if f5 doesnt work: + +1. Execute `npm run watch` from within the vscode directory + Aside: Running `npm run watch` or `npm run build` the extension is compiled into dist (extension.js) + Changing code within extension is hot-reloaded + Modifying extensions.js will not hot-reload + source file src/extension.ts +2. Wait for completion +3. Hit play from the left nav + +New code changes are automatically rebuilt if you have `watch` running, however the new VSCode Plugin-enabled window will not reflect changes until reloaded. +Manual reload from new window: "Developer: Reload Window" Default hotkey: cmd + R + +The communication between UI and extension done via the broker (see webview.postMessage) +Web view uses react (carry-over from the hackweek project courtesy of Roman and Prakhar) + +## Structure + +Extention.ts main entry point, calls sidebar.ts and workflow.ts +sidebar.ts loads the UI from the webviews folder +workflow.ts is the driving component (logic source) +cli.ts wraps CLI methods, importing from firebase-tools/src + +When workflow.ts needs to execute some CLI command, it defers to cli.ts + +## State + +currentOptions maintains the currentState of the plugin and is passed as a whole object to populate calls to the firebase-tools methods +`prepare` in the command includes a lot of + +## Logic + +Calling firebase-tools in general follows the stuff: + +1. instead of calling `before`, call `requireAuth` instead + requireAuth is a prerequisite for the plugin UI, needed + Zero-state (before login) directs the user to sign in with google (using firebase-tools CLI) +2. prepare is an implicit command in the cmd class +3. action + +requireAuth -> login with service account or check that you're already logged in via firebase-tools + +## Open issues + +Login changes in the CLI are not immediately reflected in the Plugin, requires restart +If logged-out in the middle of a plugin session, handle requireAuth errors gracefully +Plugin startup is flaky sometimes +Unit/Integration tests are not developed +Code cleanliness/structure TODOs +tsconfig.json's rootDirs includes ["src", "../src", "common"] which causes some issues with import autocomplete +Three package.jsons - one for monospace and one for the standalone plugin, and then root to copy the correct version diff --git a/firebase-vscode/common/firebaserc.ts b/firebase-vscode/common/firebaserc.ts new file mode 100644 index 00000000000..441be9895fa --- /dev/null +++ b/firebase-vscode/common/firebaserc.ts @@ -0,0 +1,2 @@ +import { RCData } from '../../src/rc'; +export interface FirebaseRC extends Partial {} diff --git a/firebase-vscode/common/messaging/broker.ts b/firebase-vscode/common/messaging/broker.ts new file mode 100644 index 00000000000..2d3c3edfc77 --- /dev/null +++ b/firebase-vscode/common/messaging/broker.ts @@ -0,0 +1,87 @@ +import { MessageParamsMap } from "./protocol"; +import { Listener, Message, MessageListeners } from "./types"; +import { Webview } from "vscode"; + +const isObject = (val: any): boolean => typeof val === "object" && val !== null; + +type Receiver = {} | Webview; + +export abstract class Broker< + OutgoingMessages extends MessageParamsMap, + IncomingMessages extends MessageParamsMap, + R extends Receiver +> { + protected readonly listeners: MessageListeners = {}; + + abstract sendMessage(message: T, data: OutgoingMessages[T]): void; + registerReceiver(receiver: R): void { } + + addListener(message: string, cb: Listener): void { + if (!this.listeners[message]) { + this.listeners[message] = { listeners: [] }; + } + this.listeners[message].listeners.push(cb); + } + + executeListeners(message: Message) { + if (message === undefined || !isObject(message) || !message.command) { + return; + } + + const d = message; + + if (this.listeners[d.command] === undefined) { + return; + } + + for (const listener of this.listeners[d.command].listeners) { + d.data === undefined ? listener() : listener(d.data); + }; + } + + delete(): void { } +} + +export interface BrokerImpl< + OutgoingMessages, + IncomingMessages, + R extends Receiver +> { + send( + message: E, + args?: OutgoingMessages[E] + ): void; + registerReceiver(receiver: R): void; + on( + message: Extract, + listener: (params: IncomingMessages[E]) => void + ): void; + delete(): void; +} + +export function createBroker< + OutgoingMessages extends MessageParamsMap, + IncomingMessages extends MessageParamsMap, + R extends Receiver +>(broker: Broker): BrokerImpl { + return { + send( + message: Extract, + args?: OutgoingMessages[E] + ): void { + broker.sendMessage(message, args); + }, + registerReceiver(receiver: R): void { + broker.registerReceiver(receiver); + }, + on( + message: Extract, + listener: (params: IncomingMessages[E]) => void + ): void { + broker.addListener(message, listener); + }, + delete(): void { + broker.delete(); + } + }; +} diff --git a/firebase-vscode/common/messaging/protocol.ts b/firebase-vscode/common/messaging/protocol.ts new file mode 100644 index 00000000000..087607fdfc4 --- /dev/null +++ b/firebase-vscode/common/messaging/protocol.ts @@ -0,0 +1,122 @@ +/** + * @fileoverview Lists all possible messages that can be passed back and forth + * between two environments (VScode and Webview) + */ + +import { FirebaseConfig } from '../../../src/firebaseConfig'; +import { FirebaseRC } from "../firebaserc"; +import { User } from "../../../src/types/auth"; +import { ServiceAccountUser } from "../types"; + +export interface WebviewToExtensionParamsMap { + /** + * Ask extension for env variables + */ + getEnv: {}; + /** + * User management + */ + getUsers: {}; + addUser: {}; + logout: { email: string }; + + /** Notify extension that current user has been changed in UI. */ + requestChangeUser: { user: User | ServiceAccountUser }; + + /** Trigger project selection */ + selectProject: { email: string }; + /** + * Runs `firebase init hosting` command. + * TODO(hsubox76): Generalize to work for all `firebase init` products. + */ + selectAndInitHostingFolder: { + projectId: string, + email: string, + singleAppSupport: boolean + }; + + /** + * Get hosting channels. + */ + getChannels: {}; + + /** + * Runs `firebase deploy` for hosting. + * TODO(hsubox76): Generalize to work for all `firebase deploy` targets. + */ + hostingDeploy: { + target: string + }; + + /** + * Get currently selected Firebase project from extension runtime. + */ + getSelectedProject: {}; + + /** + * Fetches the contents of the .firebaserc and firebase.json config files. + * If either or both files do not exist, then it will return a default + * value. + */ + getFirebaseJson: {}; + + /** + * Show a UI message using the vscode interface + */ + showMessage: { msg: string, options?: {} }; + + /** + * Write a log to the extension logger. + */ + writeLog: { level: string, args: string[] }; + + /** + * Call extension runtime to open a link (a href does not work in Monospace) + */ + openLink: { + href: string + }; +} + +export interface ExtensionToWebviewParamsMap { + /** Triggered when new environment variables values are found. */ + notifyEnv: { env: { isMonospace: boolean } }; + + /** Triggered when users have been updated. */ + notifyUsers: { users: User[] }; + + /** Triggered when hosting channels have been fetched. */ + notifyChannels: { channels: any[] }; + + /** Triggered when a new project is selected */ + notifyProjectChanged: { projectId: string }; + + /** + * This can potentially call multiple webviews to notify of user selection. + */ + notifyUserChanged: { email: string }; + + /** + * Notifies webview when user has successfully selected a hosting folder + * and it has been written to firebase.json. + */ + notifyHostingFolderReady: { projectId: string, folderPath: string }; + + /** + * Notify webview of status of deployment attempt. + */ + notifyHostingDeploy: { + success: boolean, + consoleUrl?: string, + hostingUrl?: string + }; + + /** + * Notify webview of initial discovery or change in firebase.json or + * .firebaserc + */ + notifyFirebaseConfig: { firebaseJson: FirebaseConfig, firebaseRC: FirebaseRC }; + +} + +export type MessageParamsMap = WebviewToExtensionParamsMap | ExtensionToWebviewParamsMap; diff --git a/firebase-vscode/common/messaging/types.d.ts b/firebase-vscode/common/messaging/types.d.ts new file mode 100644 index 00000000000..cbae270f1c0 --- /dev/null +++ b/firebase-vscode/common/messaging/types.d.ts @@ -0,0 +1,17 @@ +import { Channel } from "../hosting/api"; +import { ExtensionToWebviewParamsMap, MessageParamsMap } from "./protocol"; + +export interface Message { + command: string; + data: M[keyof M]; +} + +export type Listener = (args?: M[keyof M]) => void; + +export interface MessageListeners { + [message: string]: { listeners: Listener[] }; +} + +export interface ChannelWithId extends Channel { + id: string; +} diff --git a/firebase-vscode/common/types.d.ts b/firebase-vscode/common/types.d.ts new file mode 100644 index 00000000000..72f8bf49c5f --- /dev/null +++ b/firebase-vscode/common/types.d.ts @@ -0,0 +1,8 @@ +export interface ServiceAccount { + user: ServiceAccountUser +} + +export interface ServiceAccountUser { + email: string; + type: 'service_account' +} diff --git a/firebase-vscode/package-lock.json b/firebase-vscode/package-lock.json new file mode 100644 index 00000000000..8b4d3788633 --- /dev/null +++ b/firebase-vscode/package-lock.json @@ -0,0 +1,9769 @@ +{ + "name": "firebase-vscode", + "version": "0.0.7", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "firebase-vscode", + "version": "0.0.7", + "devDependencies": { + "@teamsupercell/typings-for-css-modules-loader": "^2.5.1", + "@types/glob": "^8.0.0", + "@types/mocha": "^10.0.1", + "@types/node": "16.x", + "@types/react": "^18.0.9", + "@types/react-dom": "^18.0.4", + "@types/vscode": "^1.69.0", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", + "@vscode/codicons": "0.0.30", + "@vscode/test-electron": "^2.2.0", + "@vscode/webview-ui-toolkit": "^1.2.1", + "classnames": "^2.3.2", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.7.1", + "eslint": "^8.28.0", + "eslint-plugin-react": "^7.32.2", + "fork-ts-checker-webpack-plugin": "^7.3.0", + "glob": "^8.0.3", + "mini-css-extract-plugin": "^2.6.0", + "mocha": "^10.1.0", + "postcss-loader": "^7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.52.0", + "sass-loader": "^13.0.0", + "string-replace-loader": "^3.1.0", + "ts-loader": "^9.4.2", + "typescript": "^4.9.3", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1", + "webpack-merge": "^5.8.0" + }, + "engines": { + "vscode": "^1.69.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@microsoft/fast-element": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.11.0.tgz", + "integrity": "sha512-VKJYMkS5zgzHHb66sY7AFpYv6IfFhXrjQcAyNgi2ivD65My1XOhtjfKez5ELcLFRJfgZNAxvI8kE69apXERTkw==", + "dev": true + }, + "node_modules/@microsoft/fast-foundation": { + "version": "2.47.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.47.0.tgz", + "integrity": "sha512-EyFuioaZQ9ngjUNRQi8R3dIPPsaNQdUOS+tP0G7b1MJRhXmQWIitBM6IeveQA6ZvXG6H21dqgrfEWlsYrUZ2sw==", + "dev": true, + "dependencies": { + "@microsoft/fast-element": "^1.11.0", + "@microsoft/fast-web-utilities": "^5.4.1", + "tabbable": "^5.2.0", + "tslib": "^1.13.0" + } + }, + "node_modules/@microsoft/fast-react-wrapper": { + "version": "0.1.48", + "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz", + "integrity": "sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==", + "dev": true, + "dependencies": { + "@microsoft/fast-element": "^1.9.0", + "@microsoft/fast-foundation": "^2.41.1" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@microsoft/fast-web-utilities": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz", + "integrity": "sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==", + "dev": true, + "dependencies": { + "exenv-es6": "^1.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@teamsupercell/typings-for-css-modules-loader": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@teamsupercell/typings-for-css-modules-loader/-/typings-for-css-modules-loader-2.5.2.tgz", + "integrity": "sha512-3sqH2B4itcm5XgV1IHENt4NOaW7bOC1CwJr63vrdKWWyKVxNxtBM+ABVhJZYFCCVAwNy7ulA64z6HyQqw96m4A==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "loader-utils": "^1.4.2", + "schema-utils": "^2.0.1" + }, + "optionalDependencies": { + "prettier": "*" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/eslint": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz", + "integrity": "sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.12.tgz", + "integrity": "sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.0.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", + "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/vscode": { + "version": "1.75.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.1.tgz", + "integrity": "sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz", + "integrity": "sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/type-utils": "5.53.0", + "@typescript-eslint/utils": "5.53.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.53.0.tgz", + "integrity": "sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/typescript-estree": "5.53.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz", + "integrity": "sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/visitor-keys": "5.53.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz", + "integrity": "sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.53.0", + "@typescript-eslint/utils": "5.53.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.53.0.tgz", + "integrity": "sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz", + "integrity": "sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/visitor-keys": "5.53.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.53.0.tgz", + "integrity": "sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/typescript-estree": "5.53.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz", + "integrity": "sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.53.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vscode/codicons": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.30.tgz", + "integrity": "sha512-/quu8pLXEyrShoDjTImQwJ2H28y1XhANigyw7E7JvN9NNWc3XCkoIWpcb/tUhdf7XQpopLVVYbkMjXpdPPuMXg==", + "dev": true + }, + "node_modules/@vscode/test-electron": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.2.3.tgz", + "integrity": "sha512-7DmdGYQTqRNaLHKG3j56buc9DkstriY4aV0S3Zj32u0U9/T0L8vwWAC9QGCh1meu1VXDEla1ze27TkqysHGP0Q==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@vscode/webview-ui-toolkit": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.2.1.tgz", + "integrity": "sha512-ZpVqLxoFWWk8mmAN7jr1v9yjD6NGBIoflAedNSusmaViqwHZ2znKBwAwcumLOlNlqmST6QMkiTVys7O8rzfd0w==", + "dev": true, + "dependencies": { + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.38.0", + "@microsoft/fast-react-wrapper": "^0.1.18" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true, + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/call-bind": { + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001457", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz", + "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "dev": true, + "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/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", + "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.308", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.308.tgz", + "integrity": "sha512-qyTx2aDFjEni4UnRWEME9ubd2Xc9c0zerTUl/ZinvD4QPsF0S7kJTV/Es/lPCTkNX6smyYar+z/n8Cl6pFr8yQ==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/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" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", + "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/exenv-es6": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.3.0.tgz", + "integrity": "sha512-IN+XTzusCjR5VgntYFgxbxVx3WraPRnKehBFrf00cMSrtUuW9MsG9dhL6MWpY6MkjC3wVwoujfCDgZZCQwbswA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "vue-template-compiler": "*", + "webpack": "^5.11.0" + }, + "peerDependenciesMeta": { + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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==", + "dev": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", + "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/memfs": { + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", + "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "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" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "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" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rechoir/node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "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/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "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/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sass": { + "version": "1.58.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz", + "integrity": "sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", + "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dev": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/string-replace-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-3.1.0.tgz", + "integrity": "sha512-5AOMUZeX5HE/ylKDnEa/KKBqvlnFmRZudSOjVJHxhoJg9QYTwl1rECx7SLR8BBH7tfxb4Rp7EM2XVfQFxIhsbQ==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "peerDependencies": { + "webpack": "^5" + } + }, + "node_modules/string-replace-loader/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string-replace-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/string-replace-loader/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tabbable": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz", + "integrity": "sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ts-loader": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz", + "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/webpack-cli/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webpack-cli/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-cli/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-cli/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-cli/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@microsoft/fast-element": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.11.0.tgz", + "integrity": "sha512-VKJYMkS5zgzHHb66sY7AFpYv6IfFhXrjQcAyNgi2ivD65My1XOhtjfKez5ELcLFRJfgZNAxvI8kE69apXERTkw==", + "dev": true + }, + "@microsoft/fast-foundation": { + "version": "2.47.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.47.0.tgz", + "integrity": "sha512-EyFuioaZQ9ngjUNRQi8R3dIPPsaNQdUOS+tP0G7b1MJRhXmQWIitBM6IeveQA6ZvXG6H21dqgrfEWlsYrUZ2sw==", + "dev": true, + "requires": { + "@microsoft/fast-element": "^1.11.0", + "@microsoft/fast-web-utilities": "^5.4.1", + "tabbable": "^5.2.0", + "tslib": "^1.13.0" + } + }, + "@microsoft/fast-react-wrapper": { + "version": "0.1.48", + "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz", + "integrity": "sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==", + "dev": true, + "requires": { + "@microsoft/fast-element": "^1.9.0", + "@microsoft/fast-foundation": "^2.41.1" + } + }, + "@microsoft/fast-web-utilities": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz", + "integrity": "sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==", + "dev": true, + "requires": { + "exenv-es6": "^1.1.1" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@teamsupercell/typings-for-css-modules-loader": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@teamsupercell/typings-for-css-modules-loader/-/typings-for-css-modules-loader-2.5.2.tgz", + "integrity": "sha512-3sqH2B4itcm5XgV1IHENt4NOaW7bOC1CwJr63vrdKWWyKVxNxtBM+ABVhJZYFCCVAwNy7ulA64z6HyQqw96m4A==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "loader-utils": "^1.4.2", + "prettier": "*", + "schema-utils": "^2.0.1" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/eslint": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz", + "integrity": "sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "requires": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, + "@types/node": { + "version": "16.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.12.tgz", + "integrity": "sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, + "@types/react": { + "version": "18.0.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", + "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@types/vscode": { + "version": "1.75.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.1.tgz", + "integrity": "sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz", + "integrity": "sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/type-utils": "5.53.0", + "@typescript-eslint/utils": "5.53.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.53.0.tgz", + "integrity": "sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/typescript-estree": "5.53.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz", + "integrity": "sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/visitor-keys": "5.53.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz", + "integrity": "sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.53.0", + "@typescript-eslint/utils": "5.53.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.53.0.tgz", + "integrity": "sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz", + "integrity": "sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/visitor-keys": "5.53.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.53.0.tgz", + "integrity": "sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/typescript-estree": "5.53.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.53.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz", + "integrity": "sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.53.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "@vscode/codicons": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.30.tgz", + "integrity": "sha512-/quu8pLXEyrShoDjTImQwJ2H28y1XhANigyw7E7JvN9NNWc3XCkoIWpcb/tUhdf7XQpopLVVYbkMjXpdPPuMXg==", + "dev": true + }, + "@vscode/test-electron": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.2.3.tgz", + "integrity": "sha512-7DmdGYQTqRNaLHKG3j56buc9DkstriY4aV0S3Zj32u0U9/T0L8vwWAC9QGCh1meu1VXDEla1ze27TkqysHGP0Q==", + "dev": true, + "requires": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "rimraf": "^3.0.2", + "unzipper": "^0.10.11" + } + }, + "@vscode/webview-ui-toolkit": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.2.1.tgz", + "integrity": "sha512-ZpVqLxoFWWk8mmAN7jr1v9yjD6NGBIoflAedNSusmaViqwHZ2znKBwAwcumLOlNlqmST6QMkiTVys7O8rzfd0w==", + "dev": true, + "requires": { + "@microsoft/fast-element": "^1.6.2", + "@microsoft/fast-foundation": "^2.38.0", + "@microsoft/fast-react-wrapper": "^0.1.18" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true, + "requires": {} + }, + "@webpack-cli/serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dev": true, + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "dev": true + }, + "call-bind": { + "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" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001457", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz", + "integrity": "sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA==", + "dev": true + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dev": true, + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "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==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "globby": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", + "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", + "dev": true + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.4.308", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.308.tgz", + "integrity": "sha512-qyTx2aDFjEni4UnRWEME9ubd2Xc9c0zerTUl/ZinvD4QPsF0S7kJTV/Es/lPCTkNX6smyYar+z/n8Cl6pFr8yQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", + "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "exenv-es6": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "fork-ts-checker-webpack-plugin": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.3.0.tgz", + "integrity": "sha512-IN+XTzusCjR5VgntYFgxbxVx3WraPRnKehBFrf00cMSrtUuW9MsG9dhL6MWpY6MkjC3wVwoujfCDgZZCQwbswA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "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==", + "dev": true + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "requires": {} + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "immutable": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz", + "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true + }, + "is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "dev": true + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "memfs": { + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", + "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.3" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mini-css-extract-plugin": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, + "node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "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==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, + "postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + } + } + }, + "postcss-loader": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.8" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "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" + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "requires": { + "resolve": "^1.20.0" + }, + "dependencies": { + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "sass": { + "version": "1.58.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz", + "integrity": "sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-loader": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", + "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "string-replace-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-3.1.0.tgz", + "integrity": "sha512-5AOMUZeX5HE/ylKDnEa/KKBqvlnFmRZudSOjVJHxhoJg9QYTwl1rECx7SLR8BBH7tfxb4Rp7EM2XVfQFxIhsbQ==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tabbable": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "terser": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz", + "integrity": "sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "dev": true + }, + "ts-loader": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz", + "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/firebase-vscode/package.json b/firebase-vscode/package.json new file mode 100644 index 00000000000..79a701a59d8 --- /dev/null +++ b/firebase-vscode/package.json @@ -0,0 +1,115 @@ +{ + "name": "firebase-vscode", + "displayName": "firebase-vscode", + "publisher": "firebase", + "description": "VSCode Extension for Firebase", + "version": "0.0.9", + "engines": { + "vscode": "^1.69.0" + }, + "repository": "https://github.com/firebase/firebase-tools", + "sideEffects": false, + "categories": [ + "Other" + ], + "activationEvents": [ + "onStartupFinished" + ], + "main": "./dist/extension.js", + "contributes": { + "configuration": { + "title": "Firebase VS Code Extension", + "properties": { + "firebase-vscode-extension.firebaseRcFolder": { + "type": "string", + "default": "", + "description": "Firebase RC folder" + } + }, + "firebase.debug": { + "type": "boolean", + "default": false, + "description": "Logs debug-level messages to firebase-plugin-debug.log (requires restart)" + } + }, + "viewsContainers": { + "activitybar": [ + { + "id": "firebase", + "title": "Firebase", + "icon": "$(mono-firebase)" + } + ] + }, + "icons": { + "mono-firebase": { + "description": "Firebase icon", + "default": { + "fontPath": "./resources/Monicons.woff", + "fontCharacter": "\\F101" + } + } + }, + "views": { + "firebase": [ + { + "type": "webview", + "id": "firebase.sidebarView", + "name": "Firebase" + } + ] + } + }, + "scripts": { + "vscode:prepublish": "npm run build", + "copyfiles": "cp -r node_modules/@vscode/codicons/dist resources/dist", + "pkg:vsce": "node scripts/swap-pkg.js vsce && vsce package", + "pkg:monospace": "node scripts/swap-pkg.js monospace && vsce package", + "dev": "npm run copyfiles && webpack --config webpack.dev.js", + "dev:extension": "npm run copyfiles && webpack --config webpack.dev.js --config-name extension", + "dev:sidebar": "npm run copyfiles && webpack --config webpack.dev.js --config-name sidebar", + "watch": "node scripts/swap-pkg.js vsce && npm run copyfiles && webpack --config webpack.dev.js --watch", + "build": "npm run copyfiles && webpack --config webpack.prod.js --devtool hidden-source-map", + "build:extension": "webpack --config webpack.prod.js --config-name extension", + "build:sidebar": "npm run copyfiles && webpack --config webpack.prod.js --config-name sidebar", + "pretest": "npm run build && npm run lint", + "lint": "eslint src --ext ts", + "test": "node ./dist/test/runTest.js" + }, + "dependencies": { + "@vscode/codicons": "0.0.30", + "@vscode/webview-ui-toolkit": "^1.2.1", + "classnames": "^2.3.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@teamsupercell/typings-for-css-modules-loader": "^2.5.1", + "@types/glob": "^8.0.0", + "@types/mocha": "^10.0.1", + "@types/node": "16.x", + "@types/react": "^18.0.9", + "@types/react-dom": "^18.0.4", + "@types/vscode": "^1.69.0", + "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/parser": "^5.45.0", + "@vscode/test-electron": "^2.2.0", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.7.1", + "eslint": "^8.28.0", + "eslint-plugin-react": "^7.32.2", + "fork-ts-checker-webpack-plugin": "^7.3.0", + "glob": "^8.0.3", + "mini-css-extract-plugin": "^2.6.0", + "mocha": "^10.1.0", + "postcss-loader": "^7.0.0", + "sass": "^1.52.0", + "sass-loader": "^13.0.0", + "string-replace-loader": "^3.1.0", + "ts-loader": "^9.4.2", + "typescript": "^4.9.3", + "webpack": "^5.75.0", + "webpack-cli": "^5.0.1", + "webpack-merge": "^5.8.0" + } +} \ No newline at end of file diff --git a/firebase-vscode/resources/Monicons.woff b/firebase-vscode/resources/Monicons.woff new file mode 100644 index 0000000000000000000000000000000000000000..e6735ccb638c7ef0b6a97b3955a94cbd8238a4f8 GIT binary patch literal 1932 zcmZWpc{o(-1O8@4V`nOqX)Hgv_JrHDbuEP%+gQeOOO`W+2_j3r5ksSsV4Y!Tvjrsw|m`<~~0zVCg{d*1JS&pGFfamM4F-QAr55Y7aW z03PBp03n$Fe^}x1$^f8jVNd`N+8TF_M&a@9MEKrt*ewqO$GW%nm|$LN3Ia}^k> z-~>=0xH!APJ{_3r!Z73?Tr4KId7OlO{V+cbBmQmCc$u@?Q3C)F44A_i0CK+N6G90k z!}-XEFsH-UQl?&MGz0~b1K_nDtO+s=6}?XV9R!Q8<_&W!3{})T;$u)KEf(HapzVjD zf?@;9P;xAshk$i}{sCzhaDf~e2x}aee}?DBQC*&H;bD<9_^g6G5a1RjAF60waWl7pcB z@0@2Ffb$xC-SU_4Jz|y|aj-fgS|!Ly%+Ys3>0@l#jaV4$ol+a!!G)0M3YRIMjm3&> zYBYFi+cZz9niZ5*R!(c+n1{bCIbqXB8g^EC-Y6YnOPce;ee>(P_N_mct?kG5)pfEW zh<#N{xIZ@xeW5umQ=i1p>ix&ZbJc2%*E?b_tN)69v)Xc~Z*IfDw{BdR>QZ=Dg4$27@DPZN*y z4GW-ti~o5IKk>4pFp+H-C1ryV9;iyN^}Bm2*Y#Yv-RX+T@`9QV+g}OWP4rH#lPgsz z>e{7|nU0mt`mK7DW2R)f;C)fSrQMi=stlRKDEK?mH9%|#o+;JcCrIWu8S@xwbYtyU zmS~#AqY9PL;gDzdEBz@7<+n&K6xqZ&>76=zp~fKm0Ex>GN>aPpTz!Nz+clq2@GIV>kZ@{Cm#H86V0WAwLhc=hjdh95IdzMs) zuKKHsyzB9Hq@FylV79t?WYM~;sd(?x<5E*G3$rg{qUePddVj>0fxS`QUV%+D`G(&d zhq>tB0%F7I=IZ^QD~3oHn|t!t1KM7`;;?=Yk9-CLSyuwP*&WHsH}&57|P4~uxHqtDf%(+i7K4= zbQWU8xq{=9mEW)Ar*D}yj4#a$%IIQVubgjZA!(;Z{VpKCh;U6a3_Wt2BqQtzBjHVz z|3Mo@is-)$J>Po2aqJ53ts>j6*-bsJgqWDjDe}d6=2^c{Wwd%VeX>=Ek{1mi%#zw3 zr{WGJU1dAdx&q%saKwhD{5c+4R~?&0W|m?VYKQFW4os9EvniIC(c(q$`WdtI9<=?C zNzeP6fjHtvvqY}`?lb(#j`nP%Ser8~*=~0xtAy4);I`mo!Fp=f^`w_?fRkzyUw1jc zIkMJLwTxLd2_6p537xN@q8r-osU%7K^{%I7UqnQQwAy*2NWy?aw&sCuW6G><}72 ze2x@B8P`bEUC8-wV=8N?1I~b$pOZ2wXc?-dKBQLVvGC$OL*3ZtQ>iobP{)qDO{$>~vmG z_z;9h*W2Fh19@Z}UX6Wf`VokM0o RHC2o_C<$!a_bkEr{{w7sIZOZm literal 0 HcmV?d00001 diff --git a/firebase-vscode/scripts/swap-pkg.js b/firebase-vscode/scripts/swap-pkg.js new file mode 100644 index 00000000000..f8655afa9b3 --- /dev/null +++ b/firebase-vscode/scripts/swap-pkg.js @@ -0,0 +1,29 @@ +const { writeFileSync } = require("fs"); +const path = require("path"); +const pkg = require(path.join(__dirname, "../package.json")); + +let target = "vsce"; + +process.argv.forEach((arg) => { + if (arg === "vsce" || arg === "monospace") { + target = arg; + } +}); + +if (target === "vsce") { + delete pkg.extensionDependencies; + console.log( + "Removing google.monospace extensionDependency for VSCE" + " packaging." + ); +} else if (target === "monospace") { + pkg.extensionDependencies = ["google.monospace"]; + console.log( + "Adding google.monospace extensionDependency for Monospace" + " packaging." + ); +} + +writeFileSync( + path.join(__dirname, "../package.json"), + JSON.stringify(pkg, null, 2), + { encoding: "utf8" } +); diff --git a/firebase-vscode/src/cli.ts b/firebase-vscode/src/cli.ts new file mode 100644 index 00000000000..87ab28f42e8 --- /dev/null +++ b/firebase-vscode/src/cli.ts @@ -0,0 +1,214 @@ +import * as vscode from "vscode"; +import { inspect } from "util"; + +import { + getAllAccounts, + getGlobalDefaultAccount, + loginGoogle, + setGlobalDefaultAccount, +} from "../../src/auth"; +import { logoutAction } from "../../src/commands/logout"; +import { hostingChannelDeployAction } from "../../src/commands/hosting-channel-deploy"; +import { listFirebaseProjects } from "../../src/management/projects"; +import { requireAuth } from "../../src/requireAuth"; +import { deploy } from "../../src/deploy"; +import { FirebaseConfig, HostingSingle } from "../../src/firebaseConfig"; +import { FirebaseRC } from "../common/firebaserc"; +import { getDefaultHostingSite } from "../../src/getDefaultHostingSite"; +import { initAction } from "../../src/commands/init"; +import { Account, User } from "../../src/types/auth"; +import { Options } from "../../src/options"; +import { currentOptions, getCommandOptions } from "./options"; +import { setInquirerOptions } from "./stubs/inquirer-stub"; +import { ServiceAccount } from "../common/types"; +import { listChannels } from "../../src/hosting/api"; +import { ChannelWithId } from "../common/messaging/types"; +import { setEnabled } from "../../src/experiments"; +import { pluginLogger } from "./logger-wrapper"; + +/** + * Wrap the CLI's requireAuth() which is normally run before every command + * requiring user to be logged in. The CLI automatically supplies it with + * account info if found in configstore so we need to fill that part in. + */ +async function requireAuthWrapper(showError: boolean = true) { + // Try to get global default from configstore. For some reason this is + // often overwritten when restarting the extension. + let account = getGlobalDefaultAccount(); + if (!account) { + // If nothing in configstore top level, grab the first "additionalAccount" + const accounts = getAllAccounts(); + if (accounts.length > 0) { + account = accounts[0]; + setGlobalDefaultAccount(account); + } + } + // If account is still null, `requireAuth()` will use google-auth-library + // to look for the service account hopefully. + try { + const commandOptions = await getCommandOptions(undefined, { + ...currentOptions, + ...account, + }); + await requireAuth(commandOptions); + } catch (e) { + if (showError) { + pluginLogger.error('requireAuth error', e.original || e); + vscode.window.showErrorMessage("Not logged in", { + modal: true, + detail: `Log in by clicking "Sign in with Google" in the sidebar.`, + }); + } else { + // If "showError" is false, this may not be an error, just an indication + // no one is logged in. Log to "debug". + pluginLogger.debug('No user found (this may be normal), requireAuth error output:', + e.original || e); + } + return false; + } + // No accounts but no error on requireAuth means it's a service account + // (or glogin - edge case) + return true; +} + +export async function getAccounts(): Promise> { + // Get Firebase login accounts + const accounts: Array = getAllAccounts(); + pluginLogger.debug(`Found ${accounts.length} non-service accounts.`); + // Get other accounts (assuming service account for now, could also be glogin) + const otherAuthExists = await requireAuthWrapper(false); + if (otherAuthExists) { + pluginLogger.debug(`Found service account`); + accounts.push({ + user: { email: "service_account", type: "service_account" }, + }); + } + return accounts; +} + +export async function getChannels(firebaseJSON: FirebaseConfig): Promise { + if (!firebaseJSON) { + return []; + } + const loggedIn = await requireAuthWrapper(false); + if (!loggedIn) { + return []; + } + const options = { ...currentOptions }; + if (!options.project) { + return []; + } + // TODO(hsubox76): handle multiple hosting configs + if (!(firebaseJSON.hosting as HostingSingle).site) { + (firebaseJSON.hosting as HostingSingle).site = + await getDefaultHostingSite(options); + } + pluginLogger.debug( + 'Calling listChannels with params', + options.project, + (firebaseJSON.hosting as HostingSingle).site + ); + try { + const channels = await listChannels(options.project, (firebaseJSON.hosting as HostingSingle).site); + return channels.map(channel => ({ + ...channel, id: channel.name.split("/").pop() + })); + } catch (e) { + pluginLogger.error('Error on listChannels()', e); + vscode.window.showErrorMessage("Error finding hosting channels", { + modal: true, + detail: `Error finding hosting channels: ${e}`, + }); + return []; + } +} + +export async function logoutUser(email: string): Promise { + await logoutAction(email, {} as Options); +} + +/** + * Login with standard Firebase login + */ +export async function login() { + const userCredentials = await loginGoogle(true); + setGlobalDefaultAccount(userCredentials as Account); + return userCredentials as { user: User }; +} + +export async function listProjects() { + const loggedIn = await requireAuthWrapper(false); + if (!loggedIn) { + return []; + } + return listFirebaseProjects(); +} + +export async function initHosting(options: { spa: boolean; public: string }) { + await requireAuthWrapper(); + let webFrameworksOptions = {}; + if (process.env.MONOSPACE_ENV) { + pluginLogger.debug('initHosting found MONOSPACE_ENV, ' + + 'setting web frameworks options'); + // TODO(hsubox76): Also allow VS Code users to enable this manually with a UI + setEnabled('webframeworks', true); + webFrameworksOptions = { + // Should use auto-discovered framework + useDiscoveredFramework: true, + // Should set up a new framework - do not do this on Monospace + useWebFrameworks: false + }; + } + const commandOptions = await getCommandOptions(undefined, currentOptions); + const inquirerOptions = { + ...commandOptions, + ...options, + ...webFrameworksOptions, + // False for now, we can let the user decide if needed + github: false + }; + pluginLogger.debug('Calling hosting init with inquirer options', inspect(inquirerOptions)); + setInquirerOptions(inquirerOptions); + await initAction("hosting", commandOptions); +} + +export async function deployToHosting( + firebaseJSON: FirebaseConfig, + firebaseRC: FirebaseRC, + deployTarget: string +) { + if (!(await requireAuthWrapper())) { + return { success: false, hostingUrl: "", consoleUrl: "" }; + } + + // TODO(hsubox76): throw if it doesn't find firebaseJSON or the hosting field + try { + const options = { ...currentOptions }; + // TODO(hsubox76): handle multiple hosting configs + if (!(firebaseJSON.hosting as HostingSingle).site) { + pluginLogger.debug('Calling getDefaultHostingSite() with options', inspect(options)); + (firebaseJSON.hosting as HostingSingle).site = + await getDefaultHostingSite(options); + } + pluginLogger.debug('Calling getCommandOptions() with options', inspect(options)); + const commandOptions = await getCommandOptions(firebaseJSON, options); + pluginLogger.debug('Calling hosting deploy with command options', inspect(commandOptions)); + if (deployTarget === 'live') { + await deploy(["hosting"], commandOptions); + } else { + await hostingChannelDeployAction(deployTarget, commandOptions); + } + pluginLogger.debug('Hosting deploy complete'); + } catch (e) { + let message = `Error deploying to hosting`; + if (e.message) { + message += `: ${e.message}`; + } + if (e.original) { + message += ` (original: ${e.original})`; + } + pluginLogger.error(message); + return { success: false, hostingUrl: "", consoleUrl: "" }; + } + return { success: true, hostingUrl: "", consoleUrl: "" }; +} diff --git a/firebase-vscode/src/extension-broker.ts b/firebase-vscode/src/extension-broker.ts new file mode 100644 index 00000000000..7bd7d82f8cf --- /dev/null +++ b/firebase-vscode/src/extension-broker.ts @@ -0,0 +1,41 @@ +import { Webview } from "vscode"; + +import { Broker, BrokerImpl } from "../common/messaging/broker"; +import { + ExtensionToWebviewParamsMap, + WebviewToExtensionParamsMap, +} from "../common/messaging/protocol"; +import { Message } from "../common/messaging/types"; + +export type ExtensionBrokerImpl = BrokerImpl< + ExtensionToWebviewParamsMap, + WebviewToExtensionParamsMap, + Webview +>; + +export class ExtensionBroker extends Broker< + ExtensionToWebviewParamsMap, + WebviewToExtensionParamsMap, + Webview +> { + private webviews: Webview[] = []; + + sendMessage(command: string, data: ExtensionToWebviewParamsMap[keyof ExtensionToWebviewParamsMap]): void { + for (const webview of this.webviews) { + webview.postMessage({ command, data }); + } + } + + registerReceiver(receiver: Webview) { + const webview = receiver; + this.webviews.push(webview); + webview.onDidReceiveMessage( + (message: Message) => { + this.executeListeners(message); + }, null); + } + + delete(): void { + this.webviews = []; + } +} diff --git a/firebase-vscode/src/extension.ts b/firebase-vscode/src/extension.ts new file mode 100644 index 00000000000..8dababb29a0 --- /dev/null +++ b/firebase-vscode/src/extension.ts @@ -0,0 +1,30 @@ +// The module 'vscode' contains the VS Code extensibility API +// Import the module and reference it with the alias vscode in your code below +import * as vscode from "vscode"; + +import { ExtensionBroker } from "./extension-broker"; +import { createBroker } from "../common/messaging/broker"; +import { + ExtensionToWebviewParamsMap, + WebviewToExtensionParamsMap, +} from "../common/messaging/protocol"; +import { setupSidebar } from "./sidebar"; +import { setupWorkflow } from "./workflow"; +import { pluginLogger } from "./logger-wrapper"; + +const broker = createBroker< + ExtensionToWebviewParamsMap, + WebviewToExtensionParamsMap, + vscode.Webview +>(new ExtensionBroker()); + +// This method is called when your extension is activated +export function activate(context: vscode.ExtensionContext) { + pluginLogger.debug('Activating Firebase extension.'); + + setupWorkflow(context, broker); + setupSidebar(context, broker); +} + +// This method is called when your extension is deactivated +export function deactivate() {} diff --git a/firebase-vscode/src/html-scaffold.ts b/firebase-vscode/src/html-scaffold.ts new file mode 100644 index 00000000000..14edb018ef6 --- /dev/null +++ b/firebase-vscode/src/html-scaffold.ts @@ -0,0 +1,68 @@ +import { Uri, Webview } from "vscode"; + +export function getHtmlForWebview( + entryName: string, + extensionUri: Uri, + webview: Webview +) { + const scriptUri = webview.asWebviewUri( + Uri.joinPath(extensionUri, `dist/web-${entryName}.js`) + ); + const styleUri = webview.asWebviewUri( + Uri.joinPath(extensionUri, `dist/web-${entryName}.css`) + ); + const moniconWoffUri = webview.asWebviewUri( + Uri.joinPath(extensionUri, "resources/Monicons.woff") + ); + const codiconsUri = webview.asWebviewUri( + Uri.joinPath(extensionUri, "resources/dist/codicon.css") + ); + // Use a nonce to only allow a specific script to be run. + const nonce = getNonce(); + + return ` + + + + + + + + + + + + +
+ + +`; +} + +function getNonce() { + let text = ""; + const possible = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +} diff --git a/firebase-vscode/src/logger-wrapper.ts b/firebase-vscode/src/logger-wrapper.ts new file mode 100644 index 00000000000..40e9d9a0667 --- /dev/null +++ b/firebase-vscode/src/logger-wrapper.ts @@ -0,0 +1,15 @@ +import { logger as cliLogger } from "../../src/logger"; +import { setInquirerLogger } from "./stubs/inquirer-stub"; + +export const pluginLogger: Record void> = {}; + +const logLevels = ['debug', 'info', 'log', 'warn', 'error']; + +for (const logLevel of logLevels) { + pluginLogger[logLevel] = (...args) => { + const prefixedArgs = ['[Firebase Plugin]', ...args]; + cliLogger[logLevel](...prefixedArgs); + }; +} + +setInquirerLogger(pluginLogger); \ No newline at end of file diff --git a/firebase-vscode/src/options.ts b/firebase-vscode/src/options.ts new file mode 100644 index 00000000000..b2734b44abb --- /dev/null +++ b/firebase-vscode/src/options.ts @@ -0,0 +1,99 @@ +import { Config as cliConfig } from "../../src/config"; +import { FirebaseConfig } from "../../src/firebaseConfig"; +import { FirebaseRC } from "../common/firebaserc"; +import { RC } from "../../src/rc"; +import { BaseOptions, Options } from "../../src/options"; +import { Command } from "../../src/command"; +import { ExtensionContext } from "vscode"; +import { setInquirerOptions } from "./stubs/inquirer-stub"; + +/** + * User-facing CLI options + * Passed to command.prepare() + */ + +interface CliOptions extends Omit { + config: string; +} + +/** + * Final options passed to CLI command functions + * Result of command.prepare() + */ +interface CommandOptions extends Options {} + +/** + * User-facing CLI options + */ +export let currentOptions: CliOptions & { isVSCE: boolean } = { + cwd: "", + configPath: "", + only: "", + except: "", + config: "", + filteredTargets: [], + force: true, + + // Options which are present on every command + project: "", + projectAlias: "", + projectId: "", + projectNumber: "", + projectRoot: "", + account: "", + json: true, + nonInteractive: true, + interactive: false, + debug: false, + + rc: null, + isVSCE: true +}; + +export function updateOptions( + context: ExtensionContext, + firebaseJSON: FirebaseConfig, + firebaseRC: FirebaseRC +) { + // const config = new cliConfig(firebaseJSON, options); + // currentOptions.config = config; + if (firebaseJSON) { + currentOptions.configPath = `${currentOptions.cwd}/firebase.json`; + if (firebaseJSON.hosting) { + currentOptions = { + ...currentOptions, + ...firebaseJSON.hosting, + }; + } + } else { + currentOptions.configPath = ""; + } + if (firebaseRC) { + currentOptions.rc = new RC(`${currentOptions.cwd}/.firebaserc`, firebaseRC); + currentOptions.project = firebaseRC.projects?.default; + } else { + currentOptions.rc = null; + currentOptions.project = ""; + } + context.globalState.setKeysForSync(["currentOptions"]); + context.globalState.update("currentOptions", currentOptions); + setInquirerOptions(currentOptions); +} + +/** + * Temporary options to pass to a command, don't write. + * Mostly runs it through the CLI's command.prepare() options formatter. + */ +export async function getCommandOptions( + firebaseJSON: FirebaseConfig = {}, + options: CliOptions = currentOptions +): Promise { + // Use any string, it doesn't affect `prepare()`. + const command = new Command("deploy"); + let newOptions = Object.assign(options); + if (firebaseJSON.hosting) { + newOptions = Object.assign(newOptions, firebaseJSON.hosting); + } + await command.prepare(newOptions); + return newOptions as CommandOptions; +} diff --git a/firebase-vscode/src/sidebar.ts b/firebase-vscode/src/sidebar.ts new file mode 100644 index 00000000000..533bbbf4585 --- /dev/null +++ b/firebase-vscode/src/sidebar.ts @@ -0,0 +1,65 @@ +import { + CancellationToken, + commands, + ExtensionContext, + Uri, + WebviewView, + WebviewViewProvider, + WebviewViewResolveContext, + window, +} from "vscode"; +import { getHtmlForWebview } from "./html-scaffold"; +import { ExtensionBrokerImpl } from "./extension-broker"; + +export function setupSidebar( + context: ExtensionContext, + extensionBroker: ExtensionBrokerImpl +): SidebarViewProvider { + const provider = new SidebarViewProvider( + context.extensionUri, + extensionBroker + ); + context.subscriptions.push( + window.registerWebviewViewProvider( + SidebarViewProvider.viewType, + provider + ) + ); + return provider; +} + +class SidebarViewProvider implements WebviewViewProvider { + public static readonly viewType = "firebase.sidebarView"; + private _view?: WebviewView; + + constructor( + private readonly _extensionUri: Uri, + private readonly extensionBroker: ExtensionBrokerImpl + ) {} + + public resolveWebviewView( + webviewView: WebviewView, + context: WebviewViewResolveContext, + _token: CancellationToken + ) { + this._view = webviewView; + this.extensionBroker.registerReceiver(webviewView.webview); + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [this._extensionUri], + }; + webviewView.webview.html = getHtmlForWebview( + "sidebar", + this._extensionUri, + webviewView.webview + ); + webviewView.webview.onDidReceiveMessage((data) => { + switch (data.type) { + case "executeCommand": { + commands.executeCommand(data.command, ...(data.args || [])); + break; + } + } + }); + } +} diff --git a/firebase-vscode/src/stubs/empty-class.js b/firebase-vscode/src/stubs/empty-class.js new file mode 100644 index 00000000000..23451b57f03 --- /dev/null +++ b/firebase-vscode/src/stubs/empty-class.js @@ -0,0 +1,3 @@ +class Noop {} + +module.exports = Noop; diff --git a/firebase-vscode/src/stubs/empty-function.js b/firebase-vscode/src/stubs/empty-function.js new file mode 100644 index 00000000000..2fc0e18e095 --- /dev/null +++ b/firebase-vscode/src/stubs/empty-function.js @@ -0,0 +1,3 @@ +const noop = () => {}; + +module.exports = noop; diff --git a/firebase-vscode/src/stubs/inquirer-stub.js b/firebase-vscode/src/stubs/inquirer-stub.js new file mode 100644 index 00000000000..c20dfbd871e --- /dev/null +++ b/firebase-vscode/src/stubs/inquirer-stub.js @@ -0,0 +1,31 @@ +const inquirer = module.exports; + +let pluginLogger = { + debug: () => {} +}; +const optionsKey = Symbol('options'); +inquirer[optionsKey] = {}; + +inquirer.setInquirerOptions = (inquirerOptions) => { + inquirer[optionsKey] = inquirerOptions; +}; + +inquirer.setInquirerLogger = (logger) => { + pluginLogger = logger; +}; + +inquirer.prompt = async (prompts) => { + const answers = {}; + for (const prompt of prompts) { + if (inquirer[optionsKey].hasOwnProperty(prompt.name)) { + answers[prompt.name] = inquirer[optionsKey][prompt.name]; + } else { + pluginLogger.debug( + `Didn't find "${prompt.name}" in options (message:` + + ` "${prompt.message}"), defaulting to value "${prompt.default}"` + ); + answers[prompt.name] = prompt.default; + } + } + return answers; +}; diff --git a/firebase-vscode/src/stubs/marked.js b/firebase-vscode/src/stubs/marked.js new file mode 100644 index 00000000000..8a332ace85e --- /dev/null +++ b/firebase-vscode/src/stubs/marked.js @@ -0,0 +1,5 @@ +function marked() {} + +marked.setOptions = () => {}; + +export { marked }; diff --git a/firebase-vscode/src/test/runTest.ts b/firebase-vscode/src/test/runTest.ts new file mode 100644 index 00000000000..e810ed5b2ac --- /dev/null +++ b/firebase-vscode/src/test/runTest.ts @@ -0,0 +1,23 @@ +import * as path from "path"; + +import { runTests } from "@vscode/test-electron"; + +async function main() { + try { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath = path.resolve(__dirname, "../../"); + + // The path to test runner + // Passed to --extensionTestsPath + const extensionTestsPath = path.resolve(__dirname, "./suite/index"); + + // Download VS Code, unzip it and run the integration test + await runTests({ extensionDevelopmentPath, extensionTestsPath }); + } catch (err) { + console.error("Failed to run tests"); + process.exit(1); + } +} + +main(); diff --git a/firebase-vscode/src/test/suite/extension.test.ts b/firebase-vscode/src/test/suite/extension.test.ts new file mode 100644 index 00000000000..2f671d3c729 --- /dev/null +++ b/firebase-vscode/src/test/suite/extension.test.ts @@ -0,0 +1,15 @@ +import * as assert from "assert"; + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +import * as vscode from "vscode"; +// import * as myExtension from '../../extension'; + +suite("Extension Test Suite", () => { + vscode.window.showInformationMessage("Start all tests."); + + test("Sample test", () => { + assert.strictEqual(-1, [1, 2, 3].indexOf(5)); + assert.strictEqual(-1, [1, 2, 3].indexOf(0)); + }); +}); diff --git a/firebase-vscode/src/test/suite/index.ts b/firebase-vscode/src/test/suite/index.ts new file mode 100644 index 00000000000..2cb7d7d8b3b --- /dev/null +++ b/firebase-vscode/src/test/suite/index.ts @@ -0,0 +1,38 @@ +import * as path from "path"; +import * as Mocha from "mocha"; +import * as glob from "glob"; + +export function run(): Promise { + // Create the mocha test + const mocha = new Mocha({ + ui: "tdd", + color: true, + }); + + const testsRoot = path.resolve(__dirname, ".."); + + return new Promise((c, e) => { + glob("**/**.test.js", { cwd: testsRoot }, (err, files) => { + if (err) { + return e(err); + } + + // Add files to the test suite + files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); + + try { + // Run the mocha test + mocha.run((failures) => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); + } + }); + } catch (err) { + console.error(err); + e(err); + } + }); + }); +} diff --git a/firebase-vscode/src/utils.ts b/firebase-vscode/src/utils.ts new file mode 100644 index 00000000000..e7a95b8d01a --- /dev/null +++ b/firebase-vscode/src/utils.ts @@ -0,0 +1,11 @@ +import * as fs from "fs"; +import { FirebaseRC } from "../../src/firebaserc"; + +// TODO(hsubox76): use `loadRC` and `RC.save` from firebase-tools src/rc.ts +// for RC file operations +export async function writeFirebaseRCFile( + filename: string, + content: FirebaseRC +) { + fs.writeFileSync(filename, JSON.stringify(content, null, 2)); +} diff --git a/firebase-vscode/src/workflow.ts b/firebase-vscode/src/workflow.ts new file mode 100644 index 00000000000..fa799f6e64f --- /dev/null +++ b/firebase-vscode/src/workflow.ts @@ -0,0 +1,449 @@ +import * as path from "path"; +import * as fs from "fs"; +import * as vscode from "vscode"; +import { transports, format } from "winston"; +import stripAnsi from "strip-ansi"; +import { SPLAT } from "triple-beam"; +import { ExtensionContext, workspace } from "vscode"; + +import { FirebaseProjectMetadata } from "../../src/types/project"; +import { writeFirebaseRCFile } from "./utils"; +import { ExtensionBrokerImpl } from "./extension-broker"; +import { + deployToHosting, + getAccounts, + listProjects, + login, + logoutUser, + initHosting, + getChannels, +} from "./cli"; +import { User } from "../../src/types/auth"; +import { FirebaseRC } from "../../src/firebaserc"; +import { FirebaseConfig } from "../../src/firebaseConfig"; +import { currentOptions, updateOptions } from "./options"; +import { ServiceAccountUser } from "./types"; +import { selectProjectInMonospace } from "../../src/monospace"; +import { setupLoggers, tryStringify } from "../../src/utils"; +import { pluginLogger } from "./logger-wrapper"; +import { logger } from '../../src/logger'; + +let firebaseRC: FirebaseRC | null = null; +let firebaseJSON: FirebaseConfig | null = null; +let extensionContext: ExtensionContext = null; +let users: Array = []; +let currentUserEmail = ""; +// Stores a mapping from user email to list of projects for that user +let projectsUserMapping = new Map(); + +async function fetchUsers() { + const accounts = await getAccounts(); + users = accounts.map((account) => account.user); +} + +/** + * Get the user to select a project. + */ +async function promptUserForProject( + broker: ExtensionBrokerImpl, + projects: FirebaseProjectMetadata[] +) { + const items = projects.map(({ projectId }) => projectId); + + return new Promise((resolve, reject) => { + vscode.window.showQuickPick(items).then(async (projectId) => { + const project = projects.find((p) => p.projectId === projectId); + if (!project) { + if (firebaseRC?.projects?.default) { + // Don't show an error message if a project was previously selected, + // just do nothing. + resolve(null); + } + reject("Invalid project selected. Please select a project to proceed"); + } else { + resolve(project.projectId); + } + }); + }); +} + +function updateCurrentUser( + users: User[], + broker: ExtensionBrokerImpl, + newUserEmail?: string +) { + if (newUserEmail) { + if (newUserEmail === currentUserEmail) { + return currentUserEmail; + } else { + currentUserEmail = newUserEmail; + } + } + if (!newUserEmail) { + if (users.length > 0) { + currentUserEmail = users[0].email; + } else { + currentUserEmail = null; + } + } + broker.send("notifyUserChanged", { email: currentUserEmail }); + return currentUserEmail; +} + +function getRootFolders() { + if (!workspace) { + return []; + } + const folders = workspace.workspaceFolders + ? workspace.workspaceFolders.map((wf) => wf.uri.fsPath) + : []; + if (workspace.workspaceFile) { + folders.push(path.dirname(workspace.workspaceFile.fsPath)); + } + return Array.from(new Set(folders)); +} + +function getConfigFile(filename: string): T | null { + const rootFolders = getRootFolders(); + for (const folder of rootFolders) { + const jsonFilePath = path.join(folder, filename); + if (fs.existsSync(jsonFilePath)) { + const fileText = fs.readFileSync(jsonFilePath, "utf-8"); + try { + const result = JSON.parse(fileText); + currentOptions.cwd = folder; + return result; + } catch (e) { + pluginLogger.error(`Error parsing JSON in ${jsonFilePath}`); + return null; + } + } + } + // Usually there's only one root folder unless someone is using a + // multi-root VS Code workspace. + // https://code.visualstudio.com/docs/editor/multi-root-workspaces + // We were trying to play it safe up above by assigning the cwd + // based on where a .firebaserc or firebase.json was found but if + // the user hasn't run firebase init there won't be one, and without + // a cwd we won't know where to put it. + // + // TODO: prompt where we're going to save a new firebase config + // file before we do it so the user can change it + if (!currentOptions.cwd) { + currentOptions.cwd = rootFolders[0]; + } + return null; +} + +export function setupWorkflow( + context: ExtensionContext, + broker: ExtensionBrokerImpl +) { + extensionContext = context; + + // Get user-defined VSCode settings. + const workspaceConfig = workspace.getConfiguration( + 'firebase', + vscode.workspace.workspaceFolders[0].uri + ); + const shouldDebug: boolean = workspaceConfig.get('debug'); + + /** + * Logging setup for logging to console and to file. + */ + // Sets up CLI logger to log to console + process.env.DEBUG = 'true'; + setupLoggers(); + // Re-implement file logger call from ../../src/bin/firebase.ts to not bring + // in the entire firebase.ts file + const rootFolders = getRootFolders(); + const filePath = path.join(rootFolders[0], 'firebase-plugin-debug.log'); + pluginLogger.info('Logging to path', filePath); + // Only log to file if firebase.debug extension setting is true. + if (shouldDebug) { + logger.add( + new transports.File({ + level: "debug", + filename: filePath, + format: format.printf((info) => { + const segments = [info.message, ...(info[SPLAT] || [])] + .map(tryStringify); + return `[${info.level}] ${stripAnsi(segments.join(" "))}`; + }), + }) + ); + } + // Read config files and store in memory. + readFirebaseConfigs(); + // Check current users state + fetchUsers(); + // Get hosting channels + fetchChannels(); + + /** + * Call pluginLogger with log arguments received from webview. + */ + broker.on("writeLog", async ({ level, args }) => { + pluginLogger[level]('(Webview)', ...args); + }); + + broker.on("getEnv", async () => { + pluginLogger.debug(`Value of process.env.MONOSPACE_ENV: ` + + `${process.env.MONOSPACE_ENV}`); + broker.send("notifyEnv", { + env: { + isMonospace: Boolean(process.env.MONOSPACE_ENV), + } + }); + }); + + broker.on("getUsers", async () => { + if (users.length === 0) { + await fetchUsers(); + } + broker.send("notifyUsers", { users }); + currentUserEmail = updateCurrentUser(users, broker); + }); + + broker.on("logout", async ({ email }: { email: string }) => { + try { + await logoutUser(email); + const accounts = await getAccounts(); + users = accounts.map((account) => account.user); + broker.send("notifyUsers", { users }); + currentUserEmail = updateCurrentUser(users, broker); + } catch (e) { + // ignored + } + }); + + broker.on("getSelectedProject", async () => { + // For now, just read the cached value. + // TODO: Extend this to reading from firebaserc + if (firebaseRC?.projects?.default) { + broker.send("notifyProjectChanged", + { projectId: firebaseRC?.projects?.default }); + } + fetchChannels(); + }); + + broker.on("showMessage", async ({ msg, options }) => { + vscode.window.showInformationMessage(msg, options); + }); + + broker.on("openLink", async ({ href }) => { + vscode.env.openExternal(vscode.Uri.parse(href)); + }); + + broker.on("addUser", async () => { + const { user } = await login(); + users.push(user); + if (users) { + broker.send("notifyUsers", { users }); + currentUserEmail = updateCurrentUser( + users, + broker, + user.email + ); + } + }); + + broker.on("requestChangeUser", ( + { user: requestedUser }: + { user: User | ServiceAccountUser } + ) => { + if (users.some((user) => user.email === requestedUser.email)) { + currentUserEmail = requestedUser.email; + broker.send("notifyUserChanged", { email: currentUserEmail }); + } + }); + + broker.on("selectProject", selectProject); + + broker.on("selectAndInitHostingFolder", selectAndInitHosting); + + broker.on("hostingDeploy", async ({ target: deployTarget }) => { + const { success, consoleUrl, hostingUrl } = await deployToHosting( + firebaseJSON, + firebaseRC, + deployTarget + ); + broker.send("notifyHostingDeploy", { success, consoleUrl, hostingUrl }); + if (success) { + fetchChannels(); + } + }); + + broker.on("getFirebaseJson", async () => { + readAndSendFirebaseConfigs(broker); + }); + + context.subscriptions.push( + setupFirebaseJsonAndRcFileSystemWatcher(broker) + ); + + async function fetchChannels() { + const channels = await getChannels(firebaseJSON); + broker.send("notifyChannels", { channels }); + } + + async function selectProject({ email }) { + let projectId; + if (process.env.MONOSPACE_ENV) { + pluginLogger.debug('selectProject: found MONOSPACE_ENV, ' + + 'prompting user using external flow'); + /** + * Monospace case: use Monospace flow + */ + const monospaceExtension = + vscode.extensions.getExtension('google.monospace'); + process.env.MONOSPACE_DAEMON_PORT = + monospaceExtension.exports.getMonospaceDaemonPort(); + try { + projectId = await selectProjectInMonospace({ + projectRoot: currentOptions.cwd, + project: undefined, + isVSCE: true + }); + } catch (e) { + pluginLogger.error(e); + } + } else if (email === 'service_account') { + /** + * Non-Monospace service account case: get the service account's only + * linked project. + */ + pluginLogger.debug('selectProject: MONOSPACE_ENV not found, ' + + ' but service account found'); + const projects = (await listProjects()) as FirebaseProjectMetadata[]; + projectsUserMapping.set(email, projects); + // Service accounts should only have one project. + projectId = projects[0].projectId; + } else { + /** + * Default Firebase login case, let user choose from projects that + * Firebase login has access to. + */ + pluginLogger.debug('selectProject: no service account or MONOSPACE_ENV ' + + 'found, using firebase account to list projects'); + let projects = []; + if (projectsUserMapping.has(email)) { + pluginLogger.info(`using cached projects list for ${email}`); + projects = projectsUserMapping.get(email)!; + } else { + pluginLogger.info(`fetching projects list for ${email}`); + vscode.window.showQuickPick(["Loading...."]); + projects = (await listProjects()) as FirebaseProjectMetadata[]; + projectsUserMapping.set(email, projects); + } + try { + projectId = await promptUserForProject(broker, projects); + } catch (e) { + vscode.window.showErrorMessage(e.message); + } + } + if (projectId) { + await updateFirebaseRC("default", projectId); + broker.send("notifyProjectChanged", { projectId }); + fetchChannels(); + } + } + + async function selectAndInitHosting({ projectId, singleAppSupport }) { + const options: vscode.OpenDialogOptions = { + canSelectMany: false, + openLabel: `Select distribution/public folder for ${projectId}`, + canSelectFiles: false, + canSelectFolders: true, + }; + const fileUri = await vscode.window.showOpenDialog(options); + if (fileUri && fileUri[0] && fileUri[0].fsPath) { + const publicFolderFull = fileUri[0].fsPath; + const publicFolder = publicFolderFull.substring( + currentOptions.cwd.length + 1 + ); + await initHosting({ + spa: singleAppSupport, + public: publicFolder, + }); + readAndSendFirebaseConfigs(broker); + broker.send("notifyHostingFolderReady", + { projectId, folderPath: currentOptions.cwd }); + + await fetchChannels(); + } + } +} + +/** + * Parse firebase.json and .firebaserc from the configured location, if they + * exist, and write to memory. + */ +function readFirebaseConfigs() { + firebaseRC = getConfigFile(".firebaserc"); + firebaseJSON = getConfigFile("firebase.json"); + + updateOptions(extensionContext, firebaseJSON, firebaseRC); +} + +/** + * Read Firebase configs and then send it to webviews through the given broker + */ +async function readAndSendFirebaseConfigs(broker: ExtensionBrokerImpl) { + readFirebaseConfigs(); + broker.send("notifyFirebaseConfig", + { + firebaseJson: firebaseJSON, firebaseRC + }); +} + +/** + * Write new default project to .firebaserc + */ +async function updateFirebaseRC(alias: string, projectId: string) { + if (currentOptions.cwd) { + firebaseRC = { + ...firebaseRC, + projects: { + default: firebaseRC?.projects?.default || "", + ...(firebaseRC?.projects || {}), + [alias]: projectId, + }, + }; + writeFirebaseRCFile(`${currentOptions.cwd}/.firebaserc`, firebaseRC); + updateOptions(extensionContext, firebaseJSON, firebaseRC); + } +} + +/** + * Set up a FileSystemWatcher for .firebaserc and firebase.json Also un-watch and re-watch when the + * configuration for where in the workspace the .firebaserc and firebase.json are. + */ +function setupFirebaseJsonAndRcFileSystemWatcher( + broker: ExtensionBrokerImpl +): vscode.Disposable { + // Create a new watcher + let watcher = newWatcher(); + + // Return a disposable that tears down a watcher if it's active + return { + dispose() { + watcher && watcher.dispose(); + }, + }; + + // HelperFunction to create a new watcher + function newWatcher() { + if (!currentOptions.cwd) { + return null; + } + + let watcher = workspace.createFileSystemWatcher( + path.join(currentOptions.cwd, "{firebase.json,.firebaserc}") + ); + watcher.onDidChange(async () => { + readAndSendFirebaseConfigs(broker); + }); + return watcher; + } +} diff --git a/firebase-vscode/tsconfig.json b/firebase-vscode/tsconfig.json new file mode 100644 index 00000000000..1fff794824a --- /dev/null +++ b/firebase-vscode/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": false, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "typeRoots": ["node_modules/@types", "../src/types"], + "module": "ES2015", + "moduleResolution": "node", + "target": "ES2020", + "outDir": "dist", + "lib": ["ES2020"], + "jsx": "react", + "sourceMap": true, + "rootDirs": ["src", "../src", "common"], + "strict": false /* enable all strict type-checking options */ + }, + "include": ["src/**/*", "common/**/*"] +} diff --git a/firebase-vscode/webpack.common.js b/firebase-vscode/webpack.common.js new file mode 100644 index 00000000000..ca1e75761e2 --- /dev/null +++ b/firebase-vscode/webpack.common.js @@ -0,0 +1,199 @@ +//@ts-check + +"use strict"; + +const path = require("path"); +const webpack = require("webpack"); +const fs = require("fs"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const CopyPlugin = require("copy-webpack-plugin"); +const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); + +/**@type {import('webpack').Configuration}*/ +const extensionConfig = { + name: "extension", + target: "node", // vscode extensions run in webworker context for VS Code web 📖 -> https://webpack.js.org/configuration/target/#target + + entry: "./src/extension.ts", // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ + output: { + // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ + path: path.resolve(__dirname, "dist"), + filename: "extension.js", + libraryTarget: "commonjs2", + devtoolModuleFilenameTemplate: "../[resource-path]", + }, + devtool: "source-map", + externals: { + vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ + }, + resolve: { + // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader + // mainFields: ['browser', 'module', 'main'], // look for `browser` entry point in imported node modules + mainFields: ["main", "module"], + extensions: [".ts", ".js"], + alias: { + // provides alternate implementation for node module and source files + "proxy-agent": path.resolve(__dirname, 'src/stubs/empty-class.js'), + "marked-terminal": path.resolve(__dirname, 'src/stubs/empty-class.js'), + // "ora": path.resolve(__dirname, 'src/stubs/empty-function.js'), + "commander": path.resolve(__dirname, 'src/stubs/empty-class.js'), + "inquirer": path.resolve(__dirname, 'src/stubs/inquirer-stub.js'), + // This is used for Github deploy to hosting - will need to restore + // or find another solution if we add that feature. + "libsodium-wrappers": path.resolve(__dirname, 'src/stubs/empty-class.js'), + "marked": path.resolve(__dirname, 'src/stubs/marked.js') + }, + fallback: { + // Webpack 5 no longer polyfills Node.js core modules automatically. + // see https://webpack.js.org/configuration/resolve/#resolvefallback + // for the list of Node.js core module polyfills. + }, + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: [/node_modules/], + use: [ + { + loader: "ts-loader", + }, + ], + }, + { + test: /\.ts$/, + loader: "string-replace-loader", + options: { + multiple: [ + { + search: /(\.|\.\.)[\.\/]+templates/g, + replace: "./templates", + }, + { + search: /(\.|\.\.)[\.\/]+schema/g, + replace: "./schema", + }, + { + search: /Configstore\(pkg\.name\)/g, + replace: "Configstore('firebase-tools')", + }, + // TODO(hsubox76): replace with something more robust + { + search: "childProcess.spawn(translatedCommand", + replace: "childProcess.spawn(escapedCommand" + } + ], + }, + }, + ], + }, + plugins: [ + new CopyPlugin({ + patterns: [ + { + from: "../templates", + to: "./templates", + }, + { + from: "../schema", + to: "./schema", + } + ], + }) + ], + infrastructureLogging: { + level: "log", // enables logging required for problem matchers + }, +}; + +function makeWebConfig(entryName) { + return { + name: entryName, + mode: "none", // this leaves the source code as close as possible to the original (when packaging we set this to 'production') + entry: `./webviews/${entryName}.entry.tsx`, + output: { + // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ + path: path.resolve(__dirname, "dist"), + filename: `web-${entryName}.js`, + }, + resolve: { + extensions: [".ts", ".js", ".jsx", ".tsx"], + }, + module: { + rules: [ + { + test: /\.tsx?$/, + exclude: /node_modules/, + use: ["ts-loader"], + }, + // SCSS + /** + * This generates d.ts files for the scss. See the + * "WaitForCssTypescriptPlugin" code below for the workaround required + * to prevent a race condition here. + */ + { + test: /\.scss$/, + use: [ + MiniCssExtractPlugin.loader, + { + loader: "@teamsupercell/typings-for-css-modules-loader", + options: { + banner: + "// autogenerated by typings-for-css-modules-loader. \n// Please do not change this file!", + }, + }, + { + loader: "css-loader", + options: { + modules: { + mode: "local", + localIdentName: "[local]-[hash:base64:5]", + exportLocalsConvention: "camelCaseOnly", + }, + url: false, + }, + }, + "postcss-loader", + "sass-loader", + ], + }, + ], + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: `web-${entryName}.css`, + }), + new ForkTsCheckerWebpackPlugin(), + new WaitForCssTypescriptPlugin(), + ], + devtool: "nosources-source-map", + }; +}; + +// Using the workaround for the typings-for-css-modules-loader race condition +// issue. It doesn't seem like you have to put any actual code into the hook, +// the fact that the hook runs at all seems to be enough delay for the scss.d.ts +// files to be generated. See: +// https://github.com/TeamSupercell/typings-for-css-modules-loader#typescript-does-not-find-the-typings +class WaitForCssTypescriptPlugin { + apply(compiler) { + const hooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(compiler); + + hooks.start.tap("WaitForCssTypescriptPlugin", (change) => { + console.log("Ran WaitForCssTypescriptPlugin"); + return change; + }); + } +} + +module.exports = [ + // web extensions is disabled for now. + // webExtensionConfig, + extensionConfig, + ...fs + .readdirSync("webviews") + .filter((filename) => filename.match(/\.entry\.tsx/)) + .map((filename) => filename.replace(/\.entry\.tsx/, "")) + .map((name) => makeWebConfig(name)), +]; diff --git a/firebase-vscode/webpack.dev.js b/firebase-vscode/webpack.dev.js new file mode 100644 index 00000000000..d6fb16eed92 --- /dev/null +++ b/firebase-vscode/webpack.dev.js @@ -0,0 +1,6 @@ +const { merge } = require("webpack-merge"); +const common = require("./webpack.common.js"); + +module.exports = common.map(config => merge(config, { + mode: "development" +})); diff --git a/firebase-vscode/webpack.prod.js b/firebase-vscode/webpack.prod.js new file mode 100644 index 00000000000..e4bb4e4b10f --- /dev/null +++ b/firebase-vscode/webpack.prod.js @@ -0,0 +1,7 @@ +const { merge } = require("webpack-merge"); +const common = require("./webpack.common.js"); + +module.exports = common.map(config => merge(config, { + mode: "production" +})); + diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx new file mode 100644 index 00000000000..fd6b3f59841 --- /dev/null +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -0,0 +1,161 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import React, { useEffect, useState } from "react"; +import { Spacer } from "./components/ui/Spacer"; +import { Body } from "./components/ui/Text"; +import { broker } from "./globals/html-broker"; +import { User } from "../../src/types/auth"; +import { PanelSection } from "./components/ui/PanelSection"; +import { AccountSection } from "./components/AccountSection"; +import { ProjectSection } from "./components/ProjectSection"; +import { ServiceAccountUser } from "../common/types"; +import { DeployPanel } from "./components/DeployPanel"; +import { HostingState } from "./webview-types"; +import { ChannelWithId } from "./messaging/types"; +import { webLogger } from "./globals/web-logger"; + +export function SidebarApp() { + const [projectId, setProjectId] = useState(null); + const [hostingState, setHostingState] = useState(null); + const [env, setEnv] = useState<{ isMonospace: boolean }>(); + const [channels, setChannels] = useState(null); + const [userEmail, setUserEmail] = useState(null); + /** + * null - has not finished checking yet + * empty array - finished checking, no users logged in + * non-empty array - contains logged in users + */ + const [allUsers, setAllUsers] = useState | null>(null); + const [isHostingOnboarded, setHostingOnboarded] = useState(false); + + useEffect(() => { + webLogger.debug("loading SidebarApp component"); + broker.send("getEnv"); + broker.send("getUsers"); + broker.send("getFirebaseJson"); + broker.send("getSelectedProject"); + broker.send("getChannels"); + + broker.on("notifyEnv", ({ env }) => { + webLogger.debug("notifyEnv()"); + setEnv(env); + }); + + broker.on("notifyChannels", ({ channels }) => { + webLogger.debug("notifyChannels()"); + setChannels(channels); + }); + + broker.on("notifyFirebaseConfig", ({ firebaseJson, firebaseRC }) => { + webLogger.debug("got firebase hosting", JSON.stringify(firebaseJson?.hosting)); + if (firebaseJson?.hosting) { + webLogger.debug("Detected hosting setup"); + setHostingOnboarded(true); + broker.send("showMessage", { + msg: "Auto-detected hosting setup in this folder", + }); + } else { + setHostingOnboarded(false); + } + + if (firebaseRC?.projects?.default) { + webLogger.debug("Detected project setup from existing firebaserc"); + setProjectId(firebaseRC.projects.default); + } else { + setProjectId(null); + } + }); + + broker.on("notifyUsers", ({ users }) => { + webLogger.debug("notifyUsers()"); + setAllUsers(users); + }); + + broker.on("notifyProjectChanged", ({ projectId }) => { + webLogger.debug("Project selected", projectId); + setProjectId(projectId); + }); + + broker.on("notifyUserChanged", ({ email }) => { + webLogger.debug("notifyUserChanged:", email); + setUserEmail(email); + }); + + broker.on("notifyHostingFolderReady", ({ projectId, folderPath }) => { + webLogger.debug(`notifyHostingFolderReady: ${projectId}, ${folderPath}`); + setHostingOnboarded(true); + }); + + broker.on("notifyHostingDeploy", ({ success }) => { + webLogger.debug(`notifyHostingDeploy: ${success}`); + setHostingState("deployed"); + }); + }, []); + + function setupHosting() { + broker.send("selectAndInitHostingFolder", { + projectId, + email: userEmail!, // Safe to assume user email is already there + singleAppSupport: true, + }); + }; + + const accountSection = ( + + ); + // Just render the account section loading view if it doesn't know user state + if (allUsers === null) { + return ( + <> + + {accountSection} + + ); + } + + return ( + <> + + {accountSection} + {!!userEmail && ( + + )} + {isHostingOnboarded && !!userEmail && !!projectId && ( + + )} + + {!isHostingOnboarded && !!userEmail && !!projectId && ( + { + setupHosting(); + }} + /> + )} + + ); +} + +function InitFirebasePanel({ onHostingInit }: { onHostingInit: Function }) { + return ( + + Choose a path below to get started + + onHostingInit()}> + Host your web app + + + Free web hosting with a world-class CDN for peak performance + + + ); +} diff --git a/firebase-vscode/webviews/components/AccountSection.scss b/firebase-vscode/webviews/components/AccountSection.scss new file mode 100644 index 00000000000..55f8281f40c --- /dev/null +++ b/firebase-vscode/webviews/components/AccountSection.scss @@ -0,0 +1,20 @@ +.account-row { + display: flex; + justify-content: space-between; + margin-bottom: 12px; + position: relative; + + &-label { + display: flex; + align-items: center; + } + + &-icon { + margin-right: 8px; + } + + &-project { + display: flex; + flex-direction: column; + } +} diff --git a/firebase-vscode/webviews/components/AccountSection.tsx b/firebase-vscode/webviews/components/AccountSection.tsx new file mode 100644 index 00000000000..6b92a4a8d95 --- /dev/null +++ b/firebase-vscode/webviews/components/AccountSection.tsx @@ -0,0 +1,131 @@ +import { + VSCodeLink, + VSCodeDivider, + VSCodeProgressRing, +} from "@vscode/webview-ui-toolkit/react"; +import React, { ReactElement, useState } from "react"; +import { broker } from "../globals/html-broker"; +import { Icon } from "./ui/Icon"; +import { IconButton } from "./ui/IconButton"; +import { PopupMenu, MenuItem } from "./ui/popup-menu/PopupMenu"; +import { Label } from "./ui/Text"; +import styles from "./AccountSection.scss"; +import { ServiceAccountUser } from "../../common/types"; +import { User } from "../../../src/types/auth"; + +export function AccountSection({ + userEmail, + allUsers, + isMonospace, +}: { + userEmail: string | null; + allUsers: Array | null; + isMonospace: boolean; +}) { + const [userDropdownVisible, toggleUserDropdown] = useState(false); + const usersLoaded = !!allUsers; + // Default: initial users check hasn't completed + let currentUserElement: ReactElement | string = "checking login"; + if (usersLoaded && !allUsers.length) { + // Users loaded but no user was found + if (isMonospace) { + // Monospace: this is an error, should have found a workspace + // service account + currentUserElement = "unable to find workspace service account"; + } else { + // VS Code: prompt user to log in with Google account + currentUserElement = ( broker.send("addUser")}> + Sign in with Google + ); + } + } else if (usersLoaded && allUsers.length > 0) { + // Users loaded, at least one user was found + if (isMonospace && userEmail === 'service_account') { + // TODO(hsubox76): Figure out correct wording + currentUserElement = 'workspace logged in'; + } else { + currentUserElement = userEmail; + } + } + return ( +
+ + {!usersLoaded && ( + + )} + {usersLoaded && allUsers.length > 0 && ( + <> + toggleUserDropdown(!userDropdownVisible)} + /> + {userDropdownVisible ? ( + toggleUserDropdown(false)} + /> + ) : null} + + )} +
+ ); +} + +// TODO(roman): Convert to a better menu +function UserSelectionMenu({ + userEmail, + allUsers, + onClose, +}: { + userEmail: string; + allUsers: Array; + onClose: Function; +}) { + return ( + <> + + { + broker.send("addUser"); + onClose(); + }} + > + Sign in another user... + + + {allUsers.map((user) => ( + { + broker.send("requestChangeUser", {user}); + onClose(); + }} + key={user.email} + > + {user.email} + + ))} + + { + // You can't log out of a service account + userEmail !== "service_account" && ( + { + broker.send("logout", {email: userEmail}); + onClose(); + }} + > + Sign Out {userEmail} + + ) + } + + + ); +} diff --git a/firebase-vscode/webviews/components/DeployPanel.tsx b/firebase-vscode/webviews/components/DeployPanel.tsx new file mode 100644 index 00000000000..21dfad5a806 --- /dev/null +++ b/firebase-vscode/webviews/components/DeployPanel.tsx @@ -0,0 +1,186 @@ +import { + VSCodeButton, + VSCodeDivider, + VSCodeProgressRing, + VSCodeLink, + VSCodeRadio, + VSCodeRadioGroup, + VSCodeTextField, +} from "@vscode/webview-ui-toolkit/react"; +import cn from "classnames"; +import React, { useEffect, useState } from "react"; +import { Icon } from "./ui/Icon"; +import { Spacer } from "./ui/Spacer"; +import { Label } from "./ui/Text"; +import { broker } from "../globals/html-broker"; +import styles from "../sidebar.entry.scss"; +import { PanelSection } from "./ui/PanelSection"; +import { HostingState } from "../webview-types"; +import { ChannelWithId } from "../messaging/types"; +import { ExternalLink } from "./ui/ExternalLink"; + +interface DeployInfo { + date: string; + channelId: string; +} + +export function DeployPanel({ + hostingState, + setHostingState, + projectId, + channels, +}: { + hostingState: HostingState; + setHostingState: (hostingState: HostingState) => void; + projectId: string; + channels: ChannelWithId[]; +}) { + const [deployTarget, setDeployTarget] = useState("live"); + const [newPreviewChannel, setNewPreviewChannel] = useState(""); + const [deployedInfo, setDeployedInfo] = useState(null); + + useEffect(() => { + if (hostingState === "deployed") { + setDeployedInfo({ + date: new Date().toLocaleDateString(), + channelId: deployTarget === "new" ? newPreviewChannel : deployTarget, + }); + setNewPreviewChannel(""); + } + }, [hostingState]); + + if (!channels || channels.length === 0) { + return ( + <> + + + + + + + + ); + } + + channels.sort((a, b) => (a.id === "live" ? -1 : 0)); + + const channelOptions = channels.map((channel) => ( + setDeployTarget(e.target.value)} + > + {channel.id} + + )); + let siteLink = null; + + const existingChannel = channels.find( + (channel) => channel.id === deployTarget + ); + + if (existingChannel) { + siteLink = ( + + ); + } + + return ( + <> + + + + <> + { + setHostingState("deploying"); + broker.send("hostingDeploy", { + target: + deployTarget === "new" ? newPreviewChannel : deployTarget, + }); + }} + > + Deploy to channel:{" "} + {deployTarget === "new" ? newPreviewChannel : deployTarget} + + setDeployTarget(e.target.value)} + orientation="vertical" + > + {channelOptions} + + new (type new id below) + + + { + setNewPreviewChannel(e.target.value); + }} + value={newPreviewChannel} + placeholder="new preview channel id" + > + + {hostingState !== "deploying" && ( + <> + +
+ +
+ + )} + {hostingState === "deploying" && ( + <> + +
+ + +
+ + )} + + {siteLink && ()} + +
+ + ); +} diff --git a/firebase-vscode/webviews/components/ProjectSection.tsx b/firebase-vscode/webviews/components/ProjectSection.tsx new file mode 100644 index 00000000000..108b8d9641b --- /dev/null +++ b/firebase-vscode/webviews/components/ProjectSection.tsx @@ -0,0 +1,79 @@ +import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"; +import { broker } from "../globals/html-broker"; +import { IconButton } from "./ui/IconButton"; +import { Icon } from "./ui/Icon"; +import { Label } from "./ui/Text"; +import React from "react"; +import styles from "./AccountSection.scss"; +import { ExternalLink } from "./ui/ExternalLink"; + +export function ProjectSection({ + userEmail, + projectId, +}: { + userEmail: string | null; + projectId: string | null | undefined; +}) { + return ( +
+ + {!!projectId && ( + initProjectSelection(userEmail)} + /> + )} +
+ ); +} + +export function initProjectSelection(userEmail: string | null) { + if (userEmail) { + broker.send("selectProject", { email: userEmail }); + } else { + broker.send("showMessage", { + msg: "Not logged in", + options: { + modal: true, + detail: `Log in to allow project selection. Click "Sign in with Google" in the sidebar.`, + }, + }); + return; + } +} + +export function ConnectProject({ userEmail }: { userEmail: string | null }) { + return ( + <> + initProjectSelection(userEmail)}> + Connect a Firebase project + + + ); +} + +export function ProjectInfo({ projectId }: { projectId: string }) { + return ( + <> + {projectId} + + + ); +} diff --git a/firebase-vscode/webviews/components/ui/ExternalLink.tsx b/firebase-vscode/webviews/components/ui/ExternalLink.tsx new file mode 100644 index 00000000000..085794a9587 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/ExternalLink.tsx @@ -0,0 +1,11 @@ +import React from "react"; +import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"; +import { broker } from "../../globals/html-broker"; + +export function ExternalLink({ href, text }: { href: string; text: string }) { + return ( + broker.send("openLink", { href })}> + {text} + + ); +} diff --git a/firebase-vscode/webviews/components/ui/Icon.scss b/firebase-vscode/webviews/components/ui/Icon.scss new file mode 100644 index 00000000000..192935d8723 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/Icon.scss @@ -0,0 +1,21 @@ +.monicon { + font-family: "Monicons"; + font-weight: normal; + font-style: normal; + font-size: 16px; + display: inline-block; + width: 1em; + height: 1em; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + -moz-osx-font-smoothing: grayscale; + font-feature-settings: "liga"; + speak: none; + text-decoration: inherit; +} diff --git a/firebase-vscode/webviews/components/ui/Icon.tsx b/firebase-vscode/webviews/components/ui/Icon.tsx new file mode 100644 index 00000000000..fbf8e0734e2 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/Icon.tsx @@ -0,0 +1,441 @@ +import cn from "classnames"; +import React, { HTMLAttributes, PropsWithChildren } from "react"; +import styles from "./Icon.scss"; + +export type IconName = CodiconName | MoniconName; + +export type MoniconName = "mono-firebase"; + +export type CodiconName = + | "account" + | "activate-breakpoints" + | "add" + | "archive" + | "arrow-both" + | "arrow-circle-down" + | "arrow-circle-left" + | "arrow-circle-right" + | "arrow-circle-up" + | "arrow-down" + | "arrow-left" + | "arrow-right" + | "arrow-small-down" + | "arrow-small-left" + | "arrow-small-right" + | "arrow-small-up" + | "arrow-swap" + | "arrow-up" + | "azure-devops" + | "azure" + | "beaker-stop" + | "beaker" + | "bell-dot" + | "bell" + | "bold" + | "book" + | "bookmark" + | "bracket-dot" + | "bracket-error" + | "briefcase" + | "broadcast" + | "browser" + | "bug" + | "calendar" + | "call-incoming" + | "call-outgoing" + | "case-sensitive" + | "check-all" + | "check" + | "checklist" + | "chevron-down" + | "chevron-left" + | "chevron-right" + | "chevron-up" + | "chrome-close" + | "chrome-maximize" + | "chrome-minimize" + | "chrome-restore" + | "circle-filled" + | "circle-large-filled" + | "circle-large-outline" + | "circle-outline" + | "circle-slash" + | "circuit-board" + | "clear-all" + | "clippy" + | "close-all" + | "close" + | "cloud-download" + | "cloud-upload" + | "cloud" + | "code" + | "collapse-all" + | "color-mode" + | "combine" + | "comment-discussion" + | "comment" + | "compass-active" + | "compass-dot" + | "compass" + | "copy" + | "credit-card" + | "dash" + | "dashboard" + | "database" + | "debug-all" + | "debug-alt-small" + | "debug-alt" + | "debug-breakpoint-conditional-unverified" + | "debug-breakpoint-conditional" + | "debug-breakpoint-data-unverified" + | "debug-breakpoint-data" + | "debug-breakpoint-function-unverified" + | "debug-breakpoint-function" + | "debug-breakpoint-log-unverified" + | "debug-breakpoint-log" + | "debug-breakpoint-unsupported" + | "debug-console" + | "debug-continue-small" + | "debug-continue" + | "debug-coverage" + | "debug-disconnect" + | "debug-line-by-line" + | "debug-pause" + | "debug-rerun" + | "debug-restart-frame" + | "debug-restart" + | "debug-reverse-continue" + | "debug-stackframe-active" + | "debug-stackframe-dot" + | "debug-stackframe" + | "debug-start" + | "debug-step-back" + | "debug-step-into" + | "debug-step-out" + | "debug-step-over" + | "debug-stop" + | "debug" + | "desktop-download" + | "device-camera-video" + | "device-camera" + | "device-mobile" + | "diff-added" + | "diff-ignored" + | "diff-modified" + | "diff-removed" + | "diff-renamed" + | "diff" + | "discard" + | "edit" + | "editor-layout" + | "ellipsis" + | "empty-window" + | "error-small" + | "error" + | "exclude" + | "expand-all" + | "export" + | "extensions" + | "eye-closed" + | "eye" + | "feedback" + | "file-binary" + | "file-code" + | "file-media" + | "file-pdf" + | "file-submodule" + | "file-symlink-directory" + | "file-symlink-file" + | "file-zip" + | "file" + | "files" + | "filter-filled" + | "filter" + | "flame" + | "fold-down" + | "fold-up" + | "fold" + | "folder-active" + | "folder-library" + | "folder-opened" + | "folder" + | "gear" + | "gift" + | "gist-secret" + | "git-commit" + | "git-compare" + | "git-merge" + | "git-pull-request-closed" + | "git-pull-request-create" + | "git-pull-request-draft" + | "git-pull-request" + | "github-action" + | "github-alt" + | "github-inverted" + | "github" + | "globe" + | "go-to-file" + | "grabber" + | "graph-left" + | "graph-line" + | "graph-scatter" + | "graph" + | "gripper" + | "group-by-ref-type" + | "heart" + | "history" + | "home" + | "horizontal-rule" + | "hubot" + | "inbox" + | "indent" + | "info" + | "inspect" + | "issue-draft" + | "issue-reopened" + | "issues" + | "italic" + | "jersey" + | "json" + | "kebab-vertical" + | "key" + | "law" + | "layers-active" + | "layers-dot" + | "layers" + | "layout-activitybar-left" + | "layout-activitybar-right" + | "layout-centered" + | "layout-menubar" + | "layout-panel-center" + | "layout-panel-justify" + | "layout-panel-left" + | "layout-panel-off" + | "layout-panel-right" + | "layout-panel" + | "layout-sidebar-left-off" + | "layout-sidebar-left" + | "layout-sidebar-right-off" + | "layout-sidebar-right" + | "layout-statusbar" + | "layout" + | "library" + | "lightbulb-autofix" + | "lightbulb" + | "link-external" + | "link" + | "list-filter" + | "list-flat" + | "list-ordered" + | "list-selection" + | "list-tree" + | "list-unordered" + | "live-share" + | "loading" + | "location" + | "lock-small" + | "lock" + | "magnet" + | "mail-read" + | "mail" + | "markdown" + | "megaphone" + | "mention" + | "menu" + | "merge" + | "milestone" + | "mirror" + | "mortar-board" + | "move" + | "multiple-windows" + | "mute" + | "new-file" + | "new-folder" + | "newline" + | "no-newline" + | "note" + | "notebook-template" + | "notebook" + | "octoface" + | "open-preview" + | "organization" + | "output" + | "package" + | "paintcan" + | "pass-filled" + | "pass" + | "person-add" + | "person" + | "pie-chart" + | "pin" + | "pinned-dirty" + | "pinned" + | "play-circle" + | "play" + | "plug" + | "preserve-case" + | "preview" + | "primitive-square" + | "project" + | "pulse" + | "question" + | "quote" + | "radio-tower" + | "reactions" + | "record-keys" + | "record-small" + | "record" + | "redo" + | "references" + | "refresh" + | "regex" + | "remote-explorer" + | "remote" + | "remove" + | "replace-all" + | "replace" + | "reply" + | "repo-clone" + | "repo-force-push" + | "repo-forked" + | "repo-pull" + | "repo-push" + | "repo" + | "report" + | "request-changes" + | "rocket" + | "root-folder-opened" + | "root-folder" + | "rss" + | "ruby" + | "run-above" + | "run-all" + | "run-below" + | "run-errors" + | "save-all" + | "save-as" + | "save" + | "screen-full" + | "screen-normal" + | "search-stop" + | "search" + | "server-environment" + | "server-process" + | "server" + | "settings-gear" + | "settings" + | "shield" + | "sign-in" + | "sign-out" + | "smiley" + | "sort-precedence" + | "source-control" + | "split-horizontal" + | "split-vertical" + | "squirrel" + | "star-empty" + | "star-full" + | "star-half" + | "stop-circle" + | "symbol-array" + | "symbol-boolean" + | "symbol-class" + | "symbol-color" + | "symbol-constant" + | "symbol-enum-member" + | "symbol-enum" + | "symbol-event" + | "symbol-field" + | "symbol-file" + | "symbol-interface" + | "symbol-key" + | "symbol-keyword" + | "symbol-method" + | "symbol-misc" + | "symbol-namespace" + | "symbol-numeric" + | "symbol-operator" + | "symbol-parameter" + | "symbol-property" + | "symbol-ruler" + | "symbol-snippet" + | "symbol-string" + | "symbol-structure" + | "symbol-variable" + | "sync-ignored" + | "sync" + | "table" + | "tag" + | "target" + | "tasklist" + | "telescope" + | "terminal-bash" + | "terminal-cmd" + | "terminal-debian" + | "terminal-linux" + | "terminal-powershell" + | "terminal-tmux" + | "terminal-ubuntu" + | "terminal" + | "text-size" + | "three-bars" + | "thumbsdown" + | "thumbsup" + | "tools" + | "trash" + | "triangle-down" + | "triangle-left" + | "triangle-right" + | "triangle-up" + | "twitter" + | "type-hierarchy-sub" + | "type-hierarchy-super" + | "type-hierarchy" + | "unfold" + | "ungroup-by-ref-type" + | "unlock" + | "unmute" + | "unverified" + | "variable-group" + | "verified-filled" + | "verified" + | "versions" + | "vm-active" + | "vm-connect" + | "vm-outline" + | "vm-running" + | "vm" + | "wand" + | "warning" + | "watch" + | "whitespace" + | "whole-word" + | "window" + | "word-wrap" + | "workspace-trusted" + | "workspace-unknown" + | "workspace-untrusted" + | "zoom-in" + | "zoom-out"; + +type IconProps = PropsWithChildren< + T & + HTMLAttributes & { + icon: IconName; + } +>; + +export const Icon: React.FC> = ({ + icon, + className, + ...props +}) => { + let mono = icon.startsWith("mono-"); + return mono ? ( + + {icon} + + ) : ( +
+ ); +}; diff --git a/firebase-vscode/webviews/components/ui/IconButton.tsx b/firebase-vscode/webviews/components/ui/IconButton.tsx new file mode 100644 index 00000000000..50c2c9ebff7 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/IconButton.tsx @@ -0,0 +1,30 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import React, { HTMLAttributes, PropsWithChildren } from "react"; +import { Icon, IconName } from "./Icon"; + +type TextProps = PropsWithChildren< + T & + HTMLAttributes & { + icon: IconName; + tooltip: string; + } +>; + +export const IconButton: React.FC> = ({ + icon, + tooltip, + className, + ...props +}) => { + return ( + + + + ); +}; diff --git a/firebase-vscode/webviews/components/ui/PanelSection.scss b/firebase-vscode/webviews/components/ui/PanelSection.scss new file mode 100644 index 00000000000..046c5983327 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/PanelSection.scss @@ -0,0 +1,20 @@ +.panelExpando { + appearance: none; + background-color: transparent; + display: flex; + align-items: center; + line-height: 16px; + padding: 0; + border: 0; + cursor: pointer; + gap: 4px; + color: var(--vscode-descriptionForeground); + + .panelExpandoIcon { + transition: transform 0.1s ease; + } + + &:not(.isExpanded) .panelExpandoIcon { + transform: rotate(-90deg); + } +} diff --git a/firebase-vscode/webviews/components/ui/PanelSection.tsx b/firebase-vscode/webviews/components/ui/PanelSection.tsx new file mode 100644 index 00000000000..67ef6932281 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/PanelSection.tsx @@ -0,0 +1,42 @@ +import { VSCodeDivider } from "@vscode/webview-ui-toolkit/react"; +import React, { ReactNode, useState } from "react"; +import { Icon } from "./Icon"; +import { Spacer } from "./Spacer"; +import { Heading } from "./Text"; +import cn from "classnames"; +import styles from "./PanelSection.scss"; + +export function PanelSection({ + title, + children, + isLast, +}: { + title?: ReactNode; + children: ReactNode; + isLast?: boolean; +}) { + let [isExpanded, setExpanded] = useState(true); + + return ( + <> + {title && ( + + )} + {isExpanded && ( + <> + {title && } + {children} + + {!isLast && } + + )} + + ); +} diff --git a/firebase-vscode/webviews/components/ui/Spacer.scss b/firebase-vscode/webviews/components/ui/Spacer.scss new file mode 100644 index 00000000000..cee24494810 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/Spacer.scss @@ -0,0 +1,23 @@ +.spacerxsmall { + height: var(--space-xsmall); +} + +.spacersmall { + height: var(--space-small); +} + +.spacermedium { + height: var(--space-medium); +} + +.spacerlarge { + height: var(--space-large); +} + +.spacerxlarge { + height: var(--space-xlarge); +} + +.spacerxxlarge { + height: var(--space-xxlarge); +} diff --git a/firebase-vscode/webviews/components/ui/Spacer.tsx b/firebase-vscode/webviews/components/ui/Spacer.tsx new file mode 100644 index 00000000000..4b05f1c1ae1 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/Spacer.tsx @@ -0,0 +1,14 @@ +import React from "react"; +import styles from "./Spacer.scss"; + +type SpacerSize = + | "xsmall" + | "small" + | "medium" + | "large" + | "xlarge" + | "xxlarge"; + +export function Spacer({ size = "large" }: { size: SpacerSize }) { + return
; +} diff --git a/firebase-vscode/webviews/components/ui/Text.scss b/firebase-vscode/webviews/components/ui/Text.scss new file mode 100644 index 00000000000..ffc736c76cb --- /dev/null +++ b/firebase-vscode/webviews/components/ui/Text.scss @@ -0,0 +1,94 @@ +h1, +h2, +h3, +h4, +h5, +h6, +.text { + margin: 0; + padding: 0; + font-weight: normal; + user-select: none; +} + +p, +ol, +ul { + margin: 0; + padding: 0; + line-height: var(--vscode-line-height); +} + +h1 { + font-size: 26px; + line-height: var(--vscode-line-height); + font-weight: 600; // semibold + margin: 0; +} + +h2 { + font-size: 16px; + line-height: var(--vscode-line-height); + font-weight: 500; // medium +} + +h3 { + font-size: 13px; + line-height: var(--vscode-line-height); + font-weight: 800; // heavy +} + +h4 { + font-size: 11px; + line-height: var(--vscode-line-height); + font-weight: 700; // bold + text-transform: uppercase; +} + +h5 { + font-size: 11px; + line-height: var(--vscode-line-height); + font-weight: 500; // medium + text-transform: uppercase; +} + +h6 { + font-size: 11px; + line-height: var(--vscode-line-height); + font-weight: 800; // heavy +} + +.b1 { + font-size: inherit; + line-height: var(--vscode-line-height); +} + +.b2 { + font-size: 12px; + line-height: var(--vscode-line-height); +} + +.l1 { + font-size: 14px; + line-height: var(--vscode-line-height); + font-weight: 500; // medium +} + +.l2 { + font-size: 12px; + font-weight: 700; // bold +} + +.l3 { + font-size: 11px; + font-weight: 500; // medium +} + +.l4 { + font-size: 9px; + font-weight: 700; // bold +} + +.color-secondary { + color: var(--vscode-descriptionForeground); +} diff --git a/firebase-vscode/webviews/components/ui/Text.tsx b/firebase-vscode/webviews/components/ui/Text.tsx new file mode 100644 index 00000000000..15826cd03fd --- /dev/null +++ b/firebase-vscode/webviews/components/ui/Text.tsx @@ -0,0 +1,58 @@ +import cn from "classnames"; +import React, { HTMLAttributes, PropsWithChildren } from "react"; +import styles from "./Text.scss"; + +type TextProps = PropsWithChildren< + T & + HTMLAttributes & { + secondary?: boolean; + as?: any; + } +>; + +const Text: React.FC> = ({ + secondary, + as: Component = "div", + className, + ...props +}) => { + return ( + + ); +}; + +export const Heading: React.FC> = ({ + level = 1, + ...props +}) => { + return ; +}; + +export const Label: React.FC> = ({ + level = 1, + className, + ...props +}) => { + return ( + + ); +}; + +export const Body: React.FC> = ({ + level = 1, + className, + ...props +}) => { + return ( + + ); +}; diff --git a/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.scss b/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.scss new file mode 100644 index 00000000000..d6d13894c3a --- /dev/null +++ b/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.scss @@ -0,0 +1,57 @@ +.menu { + position: absolute; + right: 0; + background-color: var(--vscode-sideBar-background); + padding: 4px 0; + margin: 0; + border-radius: 3px; + box-shadow: 0 0 0 1px var(--divider-background, black), + 0 4px 12px var(--vscode-widget-shadow); + color: var(--vscode-foreground); + z-index: 2; + list-style: none; + display: flex; + flex-direction: column; + align-items: stretch; +} + +.scrim { + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; + cursor: default; + z-index: 1; +} + +.item { + width: 100%; + text-align: left; + background-color: transparent; + appearance: none; + border: 0; + cursor: pointer; + font-family: inherit; + color: var(--color-ink); + padding: 4px 16px; + display: flex; + align-items: center; + + :global(.material-icons) { + margin-right: 12px; + color: var(--color-ink-2); + } + + &[disabled] { + cursor: not-allowed; + color: var(--color-ink-disabled); + } + + &:not([disabled]):hover { + background-color: var(--vscode-list-hoverBackground); + } + &:not([disabled]):active { + background-color: var(--vscode-list-activeSelectionBackground); + } +} diff --git a/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx b/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx new file mode 100644 index 00000000000..a1a6e7b3aa4 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx @@ -0,0 +1,57 @@ +import cn from "classnames"; +import React, { FC, HTMLAttributes, PropsWithChildren } from "react"; +import styles from "./PopupMenu.scss"; + +// TODO(hsubox76): replace this with a real, accessible Menu component + +type PopupMenuProps = PropsWithChildren< + T & + HTMLAttributes & { + show?: boolean; + onClose: Function; + } +>; + +export const PopupMenu: FC> = ({ + children, + className, + show, + onClose, +}) => { + return ( + <> + {show && ( + <> +
onClose()} /> +
    + {children} +
+ + )} + + ); +}; + +type MenuItemProps = PropsWithChildren< + T & + HTMLAttributes & { + onClick: Function; + } +>; + +export const MenuItem: FC> = ({ + className, + onClick, + children, +}) => { + return ( +
  • + +
  • + ); +}; diff --git a/firebase-vscode/webviews/globals/html-broker.ts b/firebase-vscode/webviews/globals/html-broker.ts new file mode 100644 index 00000000000..9f36261b0f6 --- /dev/null +++ b/firebase-vscode/webviews/globals/html-broker.ts @@ -0,0 +1,22 @@ +import { Broker, createBroker } from "../../common/messaging/broker"; +import { + ExtensionToWebviewParamsMap, + WebviewToExtensionParamsMap, +} from "../../common/messaging/protocol"; + +export class HtmlBroker extends Broker< + WebviewToExtensionParamsMap, ExtensionToWebviewParamsMap, {}> { + constructor(readonly vscode: any) { + super(); + window.addEventListener("message", event => this.executeListeners(event.data)); + } + + sendMessage(command: keyof WebviewToExtensionParamsMap, data: WebviewToExtensionParamsMap[keyof WebviewToExtensionParamsMap]): void { + this.vscode.postMessage({ command, data }); + } +} + +const vscode = (window as any)["acquireVsCodeApi"](); +export const broker = createBroker( + new HtmlBroker(vscode) +); diff --git a/firebase-vscode/webviews/globals/index.scss b/firebase-vscode/webviews/globals/index.scss new file mode 100644 index 00000000000..f231687635b --- /dev/null +++ b/firebase-vscode/webviews/globals/index.scss @@ -0,0 +1,12 @@ +@import "./tokens.scss"; +@import "./vscode.scss"; + +body { + background-color: transparent; + cursor: default; +} + +:global #root { + display: flex; + flex-direction: column; +} diff --git a/firebase-vscode/webviews/globals/tokens.scss b/firebase-vscode/webviews/globals/tokens.scss new file mode 100644 index 00000000000..0badec1f079 --- /dev/null +++ b/firebase-vscode/webviews/globals/tokens.scss @@ -0,0 +1,8 @@ +:root { + --space-xsmall: 2px; + --space-small: 4px; + --space-medium: 8px; + --space-large: 12px; + --space-xlarge: 16px; + --space-xxlarge: 24px; +} diff --git a/firebase-vscode/webviews/globals/vscode.scss b/firebase-vscode/webviews/globals/vscode.scss new file mode 100644 index 00000000000..7533bed4747 --- /dev/null +++ b/firebase-vscode/webviews/globals/vscode.scss @@ -0,0 +1,38 @@ +:root { + --container-padding: 20px; + --vscode-line-height: 140%; +} + +body { + margin: 0; + padding: 0 var(--container-padding); + color: var(--vscode-foreground); + font-size: var(--vscode-font-size); + line-height: var(--vscode-line-height); + font-weight: var(--vscode-font-weight); + font-family: var(--vscode-font-family); + background-color: var(--vscode-editor-background); +} + +ol, +ul { + padding-left: var(--container-padding); +} + +*:focus { + outline-color: var(--vscode-focusBorder) !important; +} + +a { + color: var(--vscode-textLink-foreground); +} + +a:hover, +a:active { + color: var(--vscode-textLink-activeForeground); +} + +code { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} diff --git a/firebase-vscode/webviews/globals/web-logger.ts b/firebase-vscode/webviews/globals/web-logger.ts new file mode 100644 index 00000000000..b6468e9b2b8 --- /dev/null +++ b/firebase-vscode/webviews/globals/web-logger.ts @@ -0,0 +1,18 @@ +import { broker } from "./html-broker"; + +type Level = 'debug' | 'info' | 'error'; +const levels: Level[] = ['debug', 'info', 'error']; + +type WebLogger = Record void>; + +const tempObject = {}; + +for (const level of levels) { + tempObject[level] = (...args: string[]) => + broker.send('writeLog', { level, args }); +} + +// Recast it now that it's populated. +const webLogger = tempObject as WebLogger; + +export { webLogger }; diff --git a/firebase-vscode/webviews/sidebar.entry.scss b/firebase-vscode/webviews/sidebar.entry.scss new file mode 100644 index 00000000000..07196d8bf56 --- /dev/null +++ b/firebase-vscode/webviews/sidebar.entry.scss @@ -0,0 +1,54 @@ +@import "./globals/index.scss"; + +a:not(:hover):not(:focus) { + text-decoration: none; +} + +.fullWidth { + width: 100%; +} + +.integrationStatus { + padding-left: 28px; + position: relative; + + &-label { + line-height: 16px; + } + + &-icon { + position: absolute; + left: 0; + top: 0; + } + + &-loading { + width: 16px; + height: 16px; + } +} + +.hosting-row { + display: flex; + justify-content: space-between; + margin-bottom: 12px; + position: relative; + + &-label { + display: flex; + align-items: center; + } + + &-icon { + margin-right: 8px; + } + + &-project { + display: flex; + flex-direction: column; + } + + &-test { + display: flex; + } +} diff --git a/firebase-vscode/webviews/sidebar.entry.tsx b/firebase-vscode/webviews/sidebar.entry.tsx new file mode 100644 index 00000000000..40d5c965ff0 --- /dev/null +++ b/firebase-vscode/webviews/sidebar.entry.tsx @@ -0,0 +1,6 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { SidebarApp } from "./SidebarApp"; + +const root = createRoot(document.getElementById("root")!); +root.render(); diff --git a/firebase-vscode/webviews/tsconfig.json b/firebase-vscode/webviews/tsconfig.json new file mode 100644 index 00000000000..eb59f3c1eac --- /dev/null +++ b/firebase-vscode/webviews/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "None", + "moduleResolution": "Node", + "target": "ES2020", + "lib": ["ES2020", "DOM"], + "esModuleInterop": true, + "jsx": "react", + "sourceMap": true, + "rootDirs": ["./", "../../src", "../common"], + "strict": false /* enable all strict type-checking options */ + }, + "include": ["../webviews/**/*", "../common/**/*"] +} diff --git a/firebase-vscode/webviews/webview-types.ts b/firebase-vscode/webviews/webview-types.ts new file mode 100644 index 00000000000..ebe64febd7a --- /dev/null +++ b/firebase-vscode/webviews/webview-types.ts @@ -0,0 +1,2 @@ + +export type HostingState = null | "deployed" | "deploying"; diff --git a/src/monospace/index.ts b/src/monospace/index.ts new file mode 100644 index 00000000000..410676cfdc4 --- /dev/null +++ b/src/monospace/index.ts @@ -0,0 +1,155 @@ +import fetch from "node-fetch"; + +import { FirebaseError } from "../error"; +import { logger } from "../logger"; +import { loadRC } from "../rc"; + +import type { + GetInitFirebaseResponse, + InitFirebaseResponse, + SetupMonospaceOptions, +} from "./interfaces"; + +const POLL_USER_RESPONSE_MILLIS = 5000; + +/** + * Integrate Firebase Plugin with Monospace’s service Account Authentication + * + * @return null if no project was authorized + * @return string if a project was authorized and isVSCE is true + * @return void if a project was authorized and isVSCE is falsy, creating + * `.firebaserc` with authorized project using the default alias + */ +export async function selectProjectInMonospace({ + projectRoot, + project, + isVSCE, +}: SetupMonospaceOptions): Promise { + const initFirebaseResponse = await initFirebase(project); + + if (initFirebaseResponse.success === false) { + throw new Error(String(initFirebaseResponse.error)); + } + + const { rid } = initFirebaseResponse; + + const authorizedProject = await pollAuthorizedProject(rid); + + if (!authorizedProject) return null; + + if (isVSCE) return authorizedProject; + + if (projectRoot) createFirebaseRc(projectRoot, authorizedProject); +} + +/** + * Since `initFirebase` pops up a dialog and waits for user response, it might + * take some time for the response to become available. Here we poll for user's + * response. + */ +async function pollAuthorizedProject(rid: string): Promise { + const getInitFirebaseRes = await getInitFirebaseResponse(rid); + + // If the user authorizes a project, `userResponse` will be available + if ("userResponse" in getInitFirebaseRes) { + if (getInitFirebaseRes.userResponse.success) { + return getInitFirebaseRes.userResponse.projectId; + } else { + return null; + } + } + + const { error } = getInitFirebaseRes; + + // Wait response: User hasn’t finished the interaction yet + if (error === "WAITING_FOR_RESPONSE") { + // wait and call back + await new Promise((res) => setTimeout(res, POLL_USER_RESPONSE_MILLIS)); + + // TODO: decide how long to ultimately wait before declaring + // that the user is never going to respond. + + return pollAuthorizedProject(rid); + } + + // FIXME: This is not being reached as the process exits before a new call is made + + // Error response: User canceled without authorizing any project + if (error === "USER_CANCELED") { + // The user hasn’t authorized any project. + // Display appropriate error message. + throw new FirebaseError("User canceled without authorizing any project"); + } + + throw new FirebaseError(`Unhandled /get-init-firebase-response error: ${error}`); +} + +/** + * Make call to init Firebase, get request id (rid) or error + */ +async function initFirebase(project?: string): Promise { + const port = getMonospaceDaemonPort(); + if (!port) throw new FirebaseError("Undefined MONOSPACE_DAEMON_PORT"); + + const initFirebaseURL = new URL(`http://localhost:${port}/init-firebase`); + + if (project) { + initFirebaseURL.searchParams.set("known_project", project); + } + + const initFirebaseRes = await fetch(initFirebaseURL.toString(), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + + const initFirebaseResponse = (await initFirebaseRes.json()) as InitFirebaseResponse; + + return initFirebaseResponse; +} + +/** + * Get response from the user - authorized project or error + */ +async function getInitFirebaseResponse(rid: string): Promise { + const port = getMonospaceDaemonPort(); + if (!port) throw new FirebaseError("Undefined MONOSPACE_DAEMON_PORT"); + + const getInitFirebaseRes = await fetch( + `http://localhost:${port}/get-init-firebase-response?rid=${rid}` + ); + + const getInitFirebaseJson = (await getInitFirebaseRes.json()) as GetInitFirebaseResponse; + + logger.debug(`/get-init-firebase-response?rid=${rid} response:`); + logger.debug(getInitFirebaseJson); + + return getInitFirebaseJson; +} + +/** + * Create a .firebaserc in the project's root with the authorized project + * as the default project + */ +function createFirebaseRc(projectDir: string, authorizedProject: string): boolean { + const firebaseRc = loadRC({ cwd: projectDir }); + + firebaseRc.addProjectAlias("default", authorizedProject); + + return firebaseRc.save(); +} + +/** + * Whether this is a Monospace environment + */ +export async function isMonospaceEnv(): Promise { + return Promise.resolve(Boolean(getMonospaceDaemonPort())); +} + +/** + * @return process.env.MONOSPACE_DAEMON_PORT + */ +function getMonospaceDaemonPort(): string | undefined { + return process.env.MONOSPACE_DAEMON_PORT; +} diff --git a/src/monospace/interfaces.ts b/src/monospace/interfaces.ts new file mode 100644 index 00000000000..d0bcd058d8b --- /dev/null +++ b/src/monospace/interfaces.ts @@ -0,0 +1,33 @@ +import type { Options } from "../options"; + +export type SetupMonospaceOptions = { + projectRoot: Options["projectRoot"]; + project: Options["project"]; + isVSCE: Options["isVSCE"]; +}; + +export type GetInitFirebaseResponse = + | { + success: true; + userResponse: { + success: true; + projectId: string; + }; + } + | { + success: true; + userResponse: { + success: false; + }; + } + | { + success: false; + error: "WAITING_FOR_RESPONSE" | "USER_CANCELED" | unknown; // TODO: define all errors + }; + +export type InitFirebaseResponse = + | { + success: true; + rid: string; + } + | { success: false; error: "NOT_INITIALIZED" | unknown }; // TODO: define all errors diff --git a/src/options.ts b/src/options.ts index 230c72bce9e..bbf422c0fc2 100644 --- a/src/options.ts +++ b/src/options.ts @@ -30,4 +30,7 @@ export interface BaseOptions { export interface Options extends BaseOptions { // TODO(samstern): Remove this once options is better typed [key: string]: unknown; + + // whether it's coming from the VS Code Extension + isVSCE?: true; } diff --git a/src/requireAuth.ts b/src/requireAuth.ts index 792fce54df1..c86a8e43324 100644 --- a/src/requireAuth.ts +++ b/src/requireAuth.ts @@ -9,6 +9,8 @@ import * as utils from "./utils"; import * as scopes from "./scopes"; import { Tokens, User } from "./types/auth"; import { setRefreshToken, setActiveAccount } from "./auth"; +import { selectProjectInMonospace, isMonospaceEnv } from "./monospace"; +import type { Options } from "./options"; const AUTH_ERROR_MESSAGE = `Command requires authentication, please run ${clc.bold( "firebase login" @@ -34,10 +36,19 @@ function getAuthClient(config: GoogleAuthOptions): GoogleAuth { * @param options CLI options. * @param authScopes scopes to be obtained. */ -async function autoAuth(options: any, authScopes: string[]): Promise { +async function autoAuth(options: Options, authScopes: string[]): Promise { const client = getAuthClient({ scopes: authScopes, projectId: options.project }); + const token = await client.getAccessToken(); token !== null ? apiv2.setAccessToken(token) : false; + + if (!options.isVSCE && (await isMonospaceEnv())) { + await selectProjectInMonospace({ + projectRoot: options.config.projectDir, + project: options.project, + isVSCE: options.isVSCE, + }); + } } /** From f5671f1d3e28a786b15f0af99efa1a3796df5513 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Mon, 12 Jun 2023 13:14:45 -0700 Subject: [PATCH 057/320] Fix firebase-vscode/package-lock.json and add it to linting. (#5965) * Fix firebase-vscode/package-lock.json and add it to linting. * Update node-test.yml --- .github/workflows/node-test.yml | 21 ++++++++- firebase-vscode/package-lock.json | 74 ++++++++++--------------------- 2 files changed, 42 insertions(+), 53 deletions(-) diff --git a/.github/workflows/node-test.yml b/.github/workflows/node-test.yml index 5a089572232..bf1bb24e8b5 100644 --- a/.github/workflows/node-test.yml +++ b/.github/workflows/node-test.yml @@ -192,13 +192,30 @@ jobs: uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - cache: npm - cache-dependency-path: npm-shrinkwrap.json - run: npm i -g npm@9.5 # --ignore-scripts prevents the `prepare` script from being run. - run: npm install --package-lock-only --ignore-scripts - run: "git diff --exit-code -- npm-shrinkwrap.json || (echo 'Error: npm-shrinkwrap.json is changed during npm install! Please make sure to use npm >= 8 and commit npm-shrinkwrap.json.' && false)" + check-package-lock-vsce: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: + - "18" + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - run: npm i -g npm@9.5 + # --ignore-scripts prevents the `prepare` script from being run. + - run: "(cd firebase-vscode && npm install --package-lock-only --ignore-scripts)" + - run: "git diff --exit-code -- firebase-vscode/package-lock.json || (echo 'Error: firebase-vscode/package-lock.json is changed during npm install! Please make sure to use npm >= 8 and commit firebase-vscode/package-lock.json.' && false)" + check-json-schema: runs-on: ubuntu-latest diff --git a/firebase-vscode/package-lock.json b/firebase-vscode/package-lock.json index 8b4d3788633..a08c836efd6 100644 --- a/firebase-vscode/package-lock.json +++ b/firebase-vscode/package-lock.json @@ -1,12 +1,19 @@ { "name": "firebase-vscode", - "version": "0.0.7", + "version": "0.0.9", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-vscode", - "version": "0.0.7", + "version": "0.0.9", + "dependencies": { + "@vscode/codicons": "0.0.30", + "@vscode/webview-ui-toolkit": "^1.2.1", + "classnames": "^2.3.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, "devDependencies": { "@teamsupercell/typings-for-css-modules-loader": "^2.5.1", "@types/glob": "^8.0.0", @@ -17,10 +24,7 @@ "@types/vscode": "^1.69.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", - "@vscode/codicons": "0.0.30", "@vscode/test-electron": "^2.2.0", - "@vscode/webview-ui-toolkit": "^1.2.1", - "classnames": "^2.3.2", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.7.1", "eslint": "^8.28.0", @@ -30,8 +34,6 @@ "mini-css-extract-plugin": "^2.6.0", "mocha": "^10.1.0", "postcss-loader": "^7.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", "sass": "^1.52.0", "sass-loader": "^13.0.0", "string-replace-loader": "^3.1.0", @@ -277,14 +279,12 @@ "node_modules/@microsoft/fast-element": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.11.0.tgz", - "integrity": "sha512-VKJYMkS5zgzHHb66sY7AFpYv6IfFhXrjQcAyNgi2ivD65My1XOhtjfKez5ELcLFRJfgZNAxvI8kE69apXERTkw==", - "dev": true + "integrity": "sha512-VKJYMkS5zgzHHb66sY7AFpYv6IfFhXrjQcAyNgi2ivD65My1XOhtjfKez5ELcLFRJfgZNAxvI8kE69apXERTkw==" }, "node_modules/@microsoft/fast-foundation": { "version": "2.47.0", "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.47.0.tgz", "integrity": "sha512-EyFuioaZQ9ngjUNRQi8R3dIPPsaNQdUOS+tP0G7b1MJRhXmQWIitBM6IeveQA6ZvXG6H21dqgrfEWlsYrUZ2sw==", - "dev": true, "dependencies": { "@microsoft/fast-element": "^1.11.0", "@microsoft/fast-web-utilities": "^5.4.1", @@ -296,7 +296,6 @@ "version": "0.1.48", "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz", "integrity": "sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==", - "dev": true, "dependencies": { "@microsoft/fast-element": "^1.9.0", "@microsoft/fast-foundation": "^2.41.1" @@ -309,7 +308,6 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz", "integrity": "sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==", - "dev": true, "dependencies": { "exenv-es6": "^1.1.1" } @@ -673,8 +671,7 @@ "node_modules/@vscode/codicons": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.30.tgz", - "integrity": "sha512-/quu8pLXEyrShoDjTImQwJ2H28y1XhANigyw7E7JvN9NNWc3XCkoIWpcb/tUhdf7XQpopLVVYbkMjXpdPPuMXg==", - "dev": true + "integrity": "sha512-/quu8pLXEyrShoDjTImQwJ2H28y1XhANigyw7E7JvN9NNWc3XCkoIWpcb/tUhdf7XQpopLVVYbkMjXpdPPuMXg==" }, "node_modules/@vscode/test-electron": { "version": "2.2.3", @@ -695,7 +692,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.2.1.tgz", "integrity": "sha512-ZpVqLxoFWWk8mmAN7jr1v9yjD6NGBIoflAedNSusmaViqwHZ2znKBwAwcumLOlNlqmST6QMkiTVys7O8rzfd0w==", - "dev": true, "dependencies": { "@microsoft/fast-element": "^1.6.2", "@microsoft/fast-foundation": "^2.38.0", @@ -1394,8 +1390,7 @@ "node_modules/classnames": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==", - "dev": true + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, "node_modules/cliui": { "version": "7.0.4", @@ -2210,8 +2205,7 @@ "node_modules/exenv-es6": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", - "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==", - "dev": true + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -3283,8 +3277,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -3460,7 +3453,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -4362,7 +4354,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -4374,7 +4365,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -4706,7 +4696,6 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -5006,8 +4995,7 @@ "node_modules/tabbable": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", - "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", - "dev": true + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" }, "node_modules/tapable": { "version": "2.2.1", @@ -5137,8 +5125,7 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -5856,14 +5843,12 @@ "@microsoft/fast-element": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.11.0.tgz", - "integrity": "sha512-VKJYMkS5zgzHHb66sY7AFpYv6IfFhXrjQcAyNgi2ivD65My1XOhtjfKez5ELcLFRJfgZNAxvI8kE69apXERTkw==", - "dev": true + "integrity": "sha512-VKJYMkS5zgzHHb66sY7AFpYv6IfFhXrjQcAyNgi2ivD65My1XOhtjfKez5ELcLFRJfgZNAxvI8kE69apXERTkw==" }, "@microsoft/fast-foundation": { "version": "2.47.0", "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.47.0.tgz", "integrity": "sha512-EyFuioaZQ9ngjUNRQi8R3dIPPsaNQdUOS+tP0G7b1MJRhXmQWIitBM6IeveQA6ZvXG6H21dqgrfEWlsYrUZ2sw==", - "dev": true, "requires": { "@microsoft/fast-element": "^1.11.0", "@microsoft/fast-web-utilities": "^5.4.1", @@ -5875,7 +5860,6 @@ "version": "0.1.48", "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz", "integrity": "sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==", - "dev": true, "requires": { "@microsoft/fast-element": "^1.9.0", "@microsoft/fast-foundation": "^2.41.1" @@ -5885,7 +5869,6 @@ "version": "5.4.1", "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz", "integrity": "sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==", - "dev": true, "requires": { "exenv-es6": "^1.1.1" } @@ -6146,8 +6129,7 @@ "@vscode/codicons": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.30.tgz", - "integrity": "sha512-/quu8pLXEyrShoDjTImQwJ2H28y1XhANigyw7E7JvN9NNWc3XCkoIWpcb/tUhdf7XQpopLVVYbkMjXpdPPuMXg==", - "dev": true + "integrity": "sha512-/quu8pLXEyrShoDjTImQwJ2H28y1XhANigyw7E7JvN9NNWc3XCkoIWpcb/tUhdf7XQpopLVVYbkMjXpdPPuMXg==" }, "@vscode/test-electron": { "version": "2.2.3", @@ -6165,7 +6147,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.2.1.tgz", "integrity": "sha512-ZpVqLxoFWWk8mmAN7jr1v9yjD6NGBIoflAedNSusmaViqwHZ2znKBwAwcumLOlNlqmST6QMkiTVys7O8rzfd0w==", - "dev": true, "requires": { "@microsoft/fast-element": "^1.6.2", "@microsoft/fast-foundation": "^2.38.0", @@ -6693,8 +6674,7 @@ "classnames": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", - "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==", - "dev": true + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, "cliui": { "version": "7.0.4", @@ -7306,8 +7286,7 @@ "exenv-es6": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", - "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==", - "dev": true + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" }, "fast-deep-equal": { "version": "3.1.3", @@ -8079,8 +8058,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "4.1.0", @@ -8218,7 +8196,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -8862,7 +8839,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "requires": { "loose-envify": "^1.1.0" } @@ -8871,7 +8847,6 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dev": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -9082,7 +9057,6 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, "requires": { "loose-envify": "^1.1.0" } @@ -9309,8 +9283,7 @@ "tabbable": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", - "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", - "dev": true + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" }, "tapable": { "version": "2.2.1", @@ -9392,8 +9365,7 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsutils": { "version": "3.21.0", From e9c312df3595acac78b1452ceb0174a196c26a61 Mon Sep 17 00:00:00 2001 From: Sairam Sakhamuri Date: Wed, 14 Jun 2023 13:39:21 -0700 Subject: [PATCH 058/320] Framework discover v3 (#5982) * Added frameworkSpec and different types used for discoving frameworks * Added repository file system to check if file exists and to read file contents * Removed comments and modified error handling. * Resolved indentation issues * Discovery: Added code analyse codebase and match to a frameworkSpec * Added test express app * FileSystem now tests file existance and reads contents from test app * Update filesystem.ts * Update filesystem.spec.ts * Update filesystem.ts * Changes to filesystem.ts * Update filesystem.spec.ts * Update filesystem.spec.ts * Updated file system current working directory * Changes to filesystem.spec.ts * Added code to test if correct frameworkSpec is recognized * Modified next commands * Removed types which aren't focused at this time. * Added mockFileSystem for testing * Added error handling * Resolved code comments * Removed lint errors * Removed lint errors * changes to desription name * Resolved error handling and test cases changes * Resolved comments * Error handling changes * Resolved comments * Resolved comments --- src/frameworks/compose/discover/filesystem.ts | 55 ++++++ .../compose/discover/frameworkMatcher.ts | 109 +++++++++++ .../compose/discover/frameworkSpec.ts | 38 ++++ src/frameworks/compose/discover/types.ts | 80 ++++++++ .../compose/discover/filesystem.spec.ts | 56 ++++++ .../compose/discover/frameworkMatcher.spec.ts | 171 ++++++++++++++++++ .../compose/discover/mockFileSystem.ts | 38 ++++ 7 files changed, 547 insertions(+) create mode 100644 src/frameworks/compose/discover/filesystem.ts create mode 100644 src/frameworks/compose/discover/frameworkMatcher.ts create mode 100644 src/frameworks/compose/discover/frameworkSpec.ts create mode 100644 src/frameworks/compose/discover/types.ts create mode 100644 src/test/frameworks/compose/discover/filesystem.spec.ts create mode 100644 src/test/frameworks/compose/discover/frameworkMatcher.spec.ts create mode 100644 src/test/frameworks/compose/discover/mockFileSystem.ts diff --git a/src/frameworks/compose/discover/filesystem.ts b/src/frameworks/compose/discover/filesystem.ts new file mode 100644 index 00000000000..b2c7b7f9b47 --- /dev/null +++ b/src/frameworks/compose/discover/filesystem.ts @@ -0,0 +1,55 @@ +import { FileSystem } from "./types"; +import { pathExists, readFile } from "fs-extra"; +import * as path from "path"; +import { FirebaseError } from "../../../error"; +import { logger } from "../../../../src/logger"; + +/** + * Find files or read file contents present in the directory. + */ +export class LocalFileSystem implements FileSystem { + private readonly existsCache: Record = {}; + private readonly contentCache: Record = {}; + + constructor(private readonly cwd: string) {} + + async exists(file: string): Promise { + try { + if (!(file in this.contentCache)) { + this.existsCache[file] = await pathExists(path.resolve(this.cwd, file)); + } + + return this.existsCache[file]; + } catch (error) { + throw new FirebaseError(`Error occured while searching for file: ${error}`); + } + } + + async read(file: string): Promise { + try { + if (!(file in this.contentCache)) { + const fileContents = await readFile(path.resolve(this.cwd, file), "utf-8"); + this.contentCache[file] = fileContents; + } + return this.contentCache[file]; + } catch (error) { + logger.error("Error occured while reading file contents."); + throw error; + } + } +} + +/** + * Convert ENOENT errors into null + */ +export async function readOrNull(fs: FileSystem, path: string): Promise { + try { + return fs.read(path); + } catch (err: any) { + if (err && typeof err === "object" && err?.code === "ENOENT") { + logger.debug("ENOENT error occured while reading file."); + return null; + } + throw new Error(`Unknown error occured while reading file: ${err}`); + } +} diff --git a/src/frameworks/compose/discover/frameworkMatcher.ts b/src/frameworks/compose/discover/frameworkMatcher.ts new file mode 100644 index 00000000000..ffe203efa4c --- /dev/null +++ b/src/frameworks/compose/discover/frameworkMatcher.ts @@ -0,0 +1,109 @@ +import { FirebaseError } from "../../../error"; +import { FrameworkSpec, FileSystem } from "./types"; +import { logger } from "../../../logger"; + +/** + * + */ +export function filterFrameworksWithDependencies( + allFrameworkSpecs: FrameworkSpec[], + dependencies: Record +): FrameworkSpec[] { + return allFrameworkSpecs.filter((framework) => { + return framework.requiredDependencies.every((dependency) => { + return dependency.name in dependencies; + }); + }); +} + +/** + * + */ +export async function filterFrameworksWithFiles( + allFrameworkSpecs: FrameworkSpec[], + fs: FileSystem +): Promise { + try { + const filteredFrameworks = []; + for (const framework of allFrameworkSpecs) { + if (!framework.requiredFiles) { + filteredFrameworks.push(framework); + continue; + } + let isRequired = true; + for (let files of framework.requiredFiles) { + files = Array.isArray(files) ? files : [files]; + for (const file of files) { + isRequired = isRequired && (await fs.exists(file)); + if (!isRequired) { + break; + } + } + } + if (isRequired) { + filteredFrameworks.push(framework); + } + } + + return filteredFrameworks; + } catch (error) { + logger.error("Error: Unable to filter frameworks based on required files", error); + throw error; + } +} + +/** + * Embeded frameworks help to resolve tiebreakers when multiple frameworks are discovered. + * Ex: "next" embeds "react", so if both frameworks are discovered, + * we can suggest "next" commands by removing its embeded framework (react). + */ +export function removeEmbededFrameworks(allFrameworkSpecs: FrameworkSpec[]): FrameworkSpec[] { + const embededFrameworkSet: Set = new Set(); + + for (const framework of allFrameworkSpecs) { + if (!framework.embedsFrameworks) { + continue; + } + for (const item of framework.embedsFrameworks) { + embededFrameworkSet.add(item); + } + } + + return allFrameworkSpecs.filter((item) => !embededFrameworkSet.has(item.id)); +} + +/** + * Identifies the best FrameworkSpec for the codebase. + */ +export async function frameworkMatcher( + runtime: string, + fs: FileSystem, + frameworks: FrameworkSpec[], + dependencies: Record +): Promise { + try { + const filterRuntimeFramework = frameworks.filter((framework) => framework.runtime === runtime); + const frameworksWithDependencies = filterFrameworksWithDependencies( + filterRuntimeFramework, + dependencies + ); + const frameworkWithFiles = await filterFrameworksWithFiles(frameworksWithDependencies, fs); + const allMatches = removeEmbededFrameworks(frameworkWithFiles); + + if (allMatches.length === 0) { + return null; + } + if (allMatches.length > 1) { + const frameworkNames = allMatches.map((framework) => framework.id); + throw new FirebaseError( + `Multiple Frameworks are matched: ${frameworkNames.join( + ", " + )} Manually set up override commands in firebase.json` + ); + } + + return allMatches[0]; + } catch (error: any) { + throw new FirebaseError(`Failed to match the correct framework: ${error}`); + } +} diff --git a/src/frameworks/compose/discover/frameworkSpec.ts b/src/frameworks/compose/discover/frameworkSpec.ts new file mode 100644 index 00000000000..70655a85b07 --- /dev/null +++ b/src/frameworks/compose/discover/frameworkSpec.ts @@ -0,0 +1,38 @@ +import { FrameworkSpec } from "./types"; + +export const frameworkSpecs: FrameworkSpec[] = [ + { + id: "express", + runtime: "nodejs", + webFrameworkId: "Express.js", + requiredDependencies: [ + { + name: "express", + }, + ], + }, + { + id: "nextjs", + runtime: "nodejs", + webFrameworkId: "Next.js", + requiredFiles: ["next.config.js", "next.config.ts"], + requiredDependencies: [ + { + name: "next", + }, + ], + commands: { + build: { + cmd: "next build", + }, + dev: { + cmd: "next dev", + env: { NODE_ENV: "dev" }, + }, + run: { + cmd: "next run", + env: { NODE_ENV: "production" }, + }, + }, + }, +]; diff --git a/src/frameworks/compose/discover/types.ts b/src/frameworks/compose/discover/types.ts new file mode 100644 index 00000000000..677e054ec27 --- /dev/null +++ b/src/frameworks/compose/discover/types.ts @@ -0,0 +1,80 @@ +export interface FileSystem { + exists(file: string): Promise; + read(file: string): Promise; +} + +export interface Runtime { + match(fs: FileSystem): Promise; + getRuntimeName(): string; + analyseCodebase(fs: FileSystem, allFrameworkSpecs: FrameworkSpec[]): Promise; +} + +export interface Command { + // Consider: string[] for series of commands that must execute successfully + // in sequence. + cmd: string; + + // Environment in which command is executed. + env?: Record; +} + +export interface LifecycleCommands { + build?: Command; + run?: Command; + dev?: Command; +} + +export interface FrameworkSpec { + id: string; + + // Only analyze Frameworks with a runtime that matches the matched runtime + runtime: string; + + // e.g. nextjs. Used to verify that Web Frameworks' legacy code and the + // FrameworkSpec agree with one another + webFrameworkId?: string; + + // List of dependencies that should be present in the project. + requiredDependencies: Array<{ + name: string; + // Version + semver?: string; + }>; + + // If a requiredFiles is an array, then one of the files in the array must match. + // This supports, for example, a file that can be a js, ts, or mjs file. + requiredFiles?: Array; + + // Any commands that this framework needs that are not standard for the + // runtime. Often times, this can be empty (e.g. depend on npm run build and + // npm run start) + commands?: LifecycleCommands; + + // We must resolve to a single framework when getting build/dev/run commands. + // embedsFrameworks helps decide tiebreakers by saying, for example, that "astro" + // can embed "svelte", so if both frameworks are discovered, monospace can + // suggest both frameworks' plugins, but should run astro's commands. + embedsFrameworks?: string[]; +} + +export interface RuntimeSpec { + // e.g. `nodejs` + id: string; + + // e.g. `node18-slim`. Depends on user code (e.g. engine field in package.json) + baseImage: string; + + // e.g. `npm install yarn typescript` + packageManagerInstallCommand?: string; + + // e.g. `npm ci`, `npm install`, `yarn` + installCommand?: string; + + // Commands to run right before exporting the container image + // e.g. npm prune --omit=dev, yarn install --production=true + exportCommands?: string[]; + + // The runtime has detected a command that should always be run irrespective of + // the framework (e.g. the "build" script always wins in Node) + detectedCommands?: LifecycleCommands; +} diff --git a/src/test/frameworks/compose/discover/filesystem.spec.ts b/src/test/frameworks/compose/discover/filesystem.spec.ts new file mode 100644 index 00000000000..db1212b3393 --- /dev/null +++ b/src/test/frameworks/compose/discover/filesystem.spec.ts @@ -0,0 +1,56 @@ +import { MockFileSystem } from "./mockFileSystem"; +import { expect } from "chai"; + +describe("MockFileSystem", () => { + let fileSystem: MockFileSystem; + + before(() => { + fileSystem = new MockFileSystem({ + "package.json": JSON.stringify({ + name: "expressapp", + version: "1.0.0", + scripts: { + test: 'echo "Error: no test specified" && exit 1', + }, + dependencies: { + express: "^4.18.2", + }, + }), + }); + }); + + describe("exists", () => { + it("should return true if file exists in the directory ", async () => { + const fileExists = await fileSystem.exists("package.json"); + + expect(fileExists).to.be.true; + expect(fileSystem.getExistsCache("package.json")).to.be.true; + }); + + it("should return false if file does not exist in the directory", async () => { + const fileExists = await fileSystem.exists("nonexistent.txt"); + + expect(fileExists).to.be.false; + }); + }); + + describe("read", () => { + it("should read and return the contents of the file", async () => { + const fileContent = await fileSystem.read("package.json"); + + const expected = JSON.stringify({ + name: "expressapp", + version: "1.0.0", + scripts: { + test: 'echo "Error: no test specified" && exit 1', + }, + dependencies: { + express: "^4.18.2", + }, + }); + + expect(fileContent).to.equal(expected); + expect(fileSystem.getContentCache("package.json")).to.equal(expected); + }); + }); +}); diff --git a/src/test/frameworks/compose/discover/frameworkMatcher.spec.ts b/src/test/frameworks/compose/discover/frameworkMatcher.spec.ts new file mode 100644 index 00000000000..bb80b326fe6 --- /dev/null +++ b/src/test/frameworks/compose/discover/frameworkMatcher.spec.ts @@ -0,0 +1,171 @@ +import { MockFileSystem } from "./mockFileSystem"; +import { expect } from "chai"; +import { + frameworkMatcher, + removeEmbededFrameworks, + filterFrameworksWithFiles, + filterFrameworksWithDependencies, +} from "../../../../frameworks/compose/discover/frameworkMatcher"; +import { frameworkSpecs } from "../../../../frameworks/compose/discover/frameworkSpec"; +import { FrameworkSpec } from "../../../../frameworks/compose/discover/types"; + +describe("frameworkMatcher", () => { + let fileSystem: MockFileSystem; + const NODE_ID = "nodejs"; + + before(() => { + fileSystem = new MockFileSystem({ + "package.json": JSON.stringify({ + name: "expressapp", + version: "1.0.0", + scripts: { + test: 'echo "Error: no test specified" && exit 1', + }, + dependencies: { + express: "^4.18.2", + }, + }), + "package-lock.json": "Unused: contents of package-lock file", + }); + }); + + describe("frameworkMatcher", () => { + it("should return express FrameworkSpec after analysing express application", async () => { + const expressDependency: Record = { + express: "^4.18.2", + }; + const matchedFramework = await frameworkMatcher( + NODE_ID, + fileSystem, + frameworkSpecs, + expressDependency + ); + const expressFrameworkSpec: FrameworkSpec = { + id: "express", + runtime: "nodejs", + webFrameworkId: "Express.js", + requiredDependencies: [ + { + name: "express", + }, + ], + }; + + expect(matchedFramework).to.deep.equal(expressFrameworkSpec); + }); + }); + + describe("removeEmbededFrameworks", () => { + it("should return frameworks after removing embeded frameworks", () => { + const allFrameworks: FrameworkSpec[] = [ + { + id: "express", + runtime: "nodejs", + requiredDependencies: [], + }, + { + id: "next", + runtime: "nodejs", + requiredDependencies: [], + embedsFrameworks: ["react"], + }, + { + id: "react", + runtime: "nodejs", + requiredDependencies: [], + }, + ]; + const actual = removeEmbededFrameworks(allFrameworks); + const expected: FrameworkSpec[] = [ + { + id: "express", + runtime: "nodejs", + requiredDependencies: [], + }, + { + id: "next", + runtime: "nodejs", + requiredDependencies: [], + embedsFrameworks: ["react"], + }, + ]; + + expect(actual).to.have.deep.members(expected); + expect(actual).to.have.length(2); + }); + }); + + describe("filterFrameworksWithFiles", () => { + it("should return frameworks having all the required files", async () => { + const allFrameworks: FrameworkSpec[] = [ + { + id: "express", + runtime: "nodejs", + requiredDependencies: [], + requiredFiles: [["package.json", "package-lock.json"]], + }, + { + id: "next", + runtime: "nodejs", + requiredDependencies: [], + requiredFiles: [["next.config.js"], "next.config.ts"], + }, + ]; + const actual = await filterFrameworksWithFiles(allFrameworks, fileSystem); + const expected: FrameworkSpec[] = [ + { + id: "express", + runtime: "nodejs", + requiredDependencies: [], + requiredFiles: [["package.json", "package-lock.json"]], + }, + ]; + + expect(actual).to.have.deep.members(expected); + expect(actual).to.have.length(1); + }); + }); + + describe("filterFrameworksWithDependencies", () => { + it("should return frameworks having required dependencies with in the project dependencies", () => { + const allFrameworks: FrameworkSpec[] = [ + { + id: "express", + runtime: "nodejs", + requiredDependencies: [ + { + name: "express", + }, + ], + }, + { + id: "next", + runtime: "nodejs", + requiredDependencies: [ + { + name: "next", + }, + ], + }, + ]; + const projectDependencies: Record = { + express: "^4.18.2", + }; + const actual = filterFrameworksWithDependencies(allFrameworks, projectDependencies); + const expected: FrameworkSpec[] = [ + { + id: "express", + runtime: "nodejs", + requiredDependencies: [ + { + name: "express", + }, + ], + }, + ]; + + expect(actual).to.have.deep.members(expected); + expect(actual).to.have.length(1); + }); + }); +}); diff --git a/src/test/frameworks/compose/discover/mockFileSystem.ts b/src/test/frameworks/compose/discover/mockFileSystem.ts new file mode 100644 index 00000000000..cdbf21d6159 --- /dev/null +++ b/src/test/frameworks/compose/discover/mockFileSystem.ts @@ -0,0 +1,38 @@ +import { FileSystem } from "../../../../frameworks/compose/discover/types"; + +export class MockFileSystem implements FileSystem { + private readonly existsCache: Record = {}; + private readonly contentCache: Record = {}; + + constructor(private readonly fileSys: Record) {} + + exists(path: string): Promise { + if (!(path in this.existsCache)) { + this.existsCache[path] = path in this.fileSys; + } + + return Promise.resolve(this.existsCache[path]); + } + + read(path: string): Promise { + if (!(path in this.contentCache)) { + if (!(path in this.fileSys)) { + const err = new Error("File path not found"); + err.cause = "ENOENT"; + throw err; + } else { + this.contentCache[path] = this.fileSys[path]; + } + } + + return Promise.resolve(this.contentCache[path]); + } + + getContentCache(path: string): string { + return this.contentCache[path]; + } + + getExistsCache(path: string): boolean { + return this.existsCache[path]; + } +} From d4d1952a119363caf7cbd8118eabc841bb5dcb8a Mon Sep 17 00:00:00 2001 From: joehan Date: Thu, 15 Jun 2023 09:59:28 -0700 Subject: [PATCH 059/320] Use firebase API to check for default bucket instead of AppEngine API (#5973) --- CHANGELOG.md | 1 + src/api.ts | 4 ---- src/deploy/storage/prepare.ts | 2 +- src/gcp/storage.ts | 14 +++++++------- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..fed1a9acf3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Fixed an issue where Storage rules could not be deployed to projects without a billing plan. (#5955) diff --git a/src/api.ts b/src/api.ts index dea5f622506..c20ead3091b 100644 --- a/src/api.ts +++ b/src/api.ts @@ -37,10 +37,6 @@ export const appDistributionOrigin = utils.envOverride( "FIREBASE_APP_DISTRIBUTION_URL", "https://firebaseappdistribution.googleapis.com" ); -export const appengineOrigin = utils.envOverride( - "FIREBASE_APPENGINE_URL", - "https://appengine.googleapis.com" -); export const authOrigin = utils.envOverride("FIREBASE_AUTH_URL", "https://accounts.google.com"); export const consoleOrigin = utils.envOverride( "FIREBASE_CONSOLE_URL", diff --git a/src/deploy/storage/prepare.ts b/src/deploy/storage/prepare.ts index 08271c0174b..6c418f59b40 100644 --- a/src/deploy/storage/prepare.ts +++ b/src/deploy/storage/prepare.ts @@ -34,7 +34,7 @@ export default async function (context: any, options: Options): Promise { const rulesDeploy = new RulesDeploy(options, RulesetServiceType.FIREBASE_STORAGE); const rulesConfigsToDeploy: any[] = []; - if (!Array.isArray(rulesConfig)) { + if (!Array.isArray(rulesConfig) && options.project) { const defaultBucket = await gcp.storage.getDefaultBucket(options.project); rulesConfig = [Object.assign(rulesConfig, { bucket: defaultBucket })]; } diff --git a/src/gcp/storage.ts b/src/gcp/storage.ts index e290ae1bf13..b50bf83eaa5 100644 --- a/src/gcp/storage.ts +++ b/src/gcp/storage.ts @@ -1,10 +1,11 @@ import { Readable } from "stream"; import * as path from "path"; -import { appengineOrigin, storageOrigin } from "../api"; +import { storageOrigin } from "../api"; import { Client } from "../apiv2"; -import { logger } from "../logger"; import { FirebaseError } from "../error"; +import { logger } from "../logger"; +import { getFirebaseProject } from "../management/projects"; /** Bucket Interface */ interface BucketResponse { @@ -138,17 +139,16 @@ interface StorageServiceAccountResponse { kind: string; } -export async function getDefaultBucket(projectId?: string): Promise { +export async function getDefaultBucket(projectId: string): Promise { try { - const appengineClient = new Client({ urlPrefix: appengineOrigin, apiVersion: "v1" }); - const resp = await appengineClient.get<{ defaultBucket: string }>(`/apps/${projectId}`); - if (resp.body.defaultBucket === "undefined") { + const metadata = await getFirebaseProject(projectId); + if (!metadata.resources?.storageBucket) { logger.debug("Default storage bucket is undefined."); throw new FirebaseError( "Your project is being set up. Please wait a minute before deploying again." ); } - return resp.body.defaultBucket; + return metadata.resources.storageBucket; } catch (err: any) { logger.info( "\n\nThere was an issue deploying your functions. Verify that your project has a Google App Engine instance setup at https://console.cloud.google.com/appengine and try again. If this issue persists, please contact support." From d7ed2a91d0c011f9d679238fd876c671523a9e22 Mon Sep 17 00:00:00 2001 From: Kai Bolay Date: Thu, 15 Jun 2023 15:58:33 -0400 Subject: [PATCH 060/320] App Distribution: Add commands to manage groups (#5978) - Added appdistribution:group:create and appdistribution:group:delete. - Added --group-alias option to appdistribution:testers:add and appdistribution:testers:remove. --- CHANGELOG.md | 4 + src/appdistribution/client.ts | 66 ++++++++++- src/commands/appdistribution-group-create.ts | 17 +++ src/commands/appdistribution-group-delete.ts | 21 ++++ src/commands/appdistribution-testers-add.ts | 13 ++- .../appdistribution-testers-remove.ts | 38 ++++--- src/commands/index.ts | 3 + src/test/appdistro/client.spec.ts | 104 +++++++++++++++++- 8 files changed, 249 insertions(+), 17 deletions(-) create mode 100644 src/commands/appdistribution-group-create.ts create mode 100644 src/commands/appdistribution-group-delete.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index fed1a9acf3c..dd655c586b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,5 @@ +- Added `appdistribution:group:create` and + `appdistribution:group:delete`. +- Added `--group-alias` option to `appdistribution:testers:add` and + `appdistribution:testers:remove`. - Fixed an issue where Storage rules could not be deployed to projects without a billing plan. (#5955) diff --git a/src/appdistribution/client.ts b/src/appdistribution/client.ts index b85a5719c1e..76bc0f2ff9d 100644 --- a/src/appdistribution/client.ts +++ b/src/appdistribution/client.ts @@ -64,6 +64,14 @@ export interface BatchRemoveTestersResponse { emails: string[]; } +export interface Group { + name: string; + displayName: string; + testerCount?: number; + releaseCount?: number; + inviteLinkCount?: number; +} + /** * Makes RPCs to the App Distribution server backend. */ @@ -166,7 +174,7 @@ export class AppDistributionClient { utils.logSuccess("distributed to testers/groups successfully"); } - async addTesters(projectName: string, emails: string[]) { + async addTesters(projectName: string, emails: string[]): Promise { try { await this.appDistroV2Client.request({ method: "POST", @@ -196,4 +204,60 @@ export class AppDistributionClient { } return apiResponse.body; } + + async createGroup(projectName: string, displayName: string, alias?: string): Promise { + let apiResponse; + try { + apiResponse = await this.appDistroV2Client.request<{ displayName: string }, Group>({ + method: "POST", + path: + alias === undefined ? `${projectName}/groups` : `${projectName}/groups?groupId=${alias}`, + body: { displayName: displayName }, + }); + } catch (err: any) { + throw new FirebaseError(`Failed to create group ${err}`); + } + return apiResponse.body; + } + + async deleteGroup(groupName: string): Promise { + try { + await this.appDistroV2Client.request({ + method: "DELETE", + path: groupName, + }); + } catch (err: any) { + throw new FirebaseError(`Failed to delete group ${err}`); + } + + utils.logSuccess(`Group deleted successfully`); + } + + async addTestersToGroup(groupName: string, emails: string[]): Promise { + try { + await this.appDistroV2Client.request({ + method: "POST", + path: `${groupName}:batchJoin`, + body: { emails: emails }, + }); + } catch (err: any) { + throw new FirebaseError(`Failed to add testers to group ${err}`); + } + + utils.logSuccess(`Testers added to group successfully`); + } + + async removeTestersFromGroup(groupName: string, emails: string[]): Promise { + try { + await this.appDistroV2Client.request({ + method: "POST", + path: `${groupName}:batchLeave`, + body: { emails: emails }, + }); + } catch (err: any) { + throw new FirebaseError(`Failed to remove testers from group ${err}`); + } + + utils.logSuccess(`Testers removed from group successfully`); + } } diff --git a/src/commands/appdistribution-group-create.ts b/src/commands/appdistribution-group-create.ts new file mode 100644 index 00000000000..493d32af836 --- /dev/null +++ b/src/commands/appdistribution-group-create.ts @@ -0,0 +1,17 @@ +import { Command } from "../command"; +import * as utils from "../utils"; +import { requireAuth } from "../requireAuth"; +import { AppDistributionClient } from "../appdistribution/client"; +import { getProjectName } from "../appdistribution/options-parser-util"; + +export const command = new Command("appdistribution:group:create [alias]") + .description("create group in project") + .before(requireAuth) + .action(async (displayName: string, alias?: string, options?: any) => { + const projectName = await getProjectName(options); + const appDistroClient = new AppDistributionClient(); + utils.logBullet(`Creating group in project`); + const group = await appDistroClient.createGroup(projectName, displayName, alias); + alias = group.name.split("/").pop(); + utils.logSuccess(`Group '${group.displayName}' (alias: ${alias}) created successfully`); + }); diff --git a/src/commands/appdistribution-group-delete.ts b/src/commands/appdistribution-group-delete.ts new file mode 100644 index 00000000000..16651d711f8 --- /dev/null +++ b/src/commands/appdistribution-group-delete.ts @@ -0,0 +1,21 @@ +import { Command } from "../command"; +import * as utils from "../utils"; +import { requireAuth } from "../requireAuth"; +import { FirebaseError } from "../error"; +import { AppDistributionClient } from "../appdistribution/client"; +import { getProjectName } from "../appdistribution/options-parser-util"; + +export const command = new Command("appdistribution:group:delete ") + .description("delete group from a project") + .before(requireAuth) + .action(async (alias: string, options: any) => { + const projectName = await getProjectName(options); + const appDistroClient = new AppDistributionClient(); + try { + utils.logBullet(`Deleting group from project`); + await appDistroClient.deleteGroup(`${projectName}/groups/${alias}`); + } catch (err: any) { + throw new FirebaseError(`Failed to delete group ${err}`); + } + utils.logSuccess(`Group ${alias} has successfully been deleted`); + }); diff --git a/src/commands/appdistribution-testers-add.ts b/src/commands/appdistribution-testers-add.ts index e9833348f2c..66a9dc76e71 100644 --- a/src/commands/appdistribution-testers-add.ts +++ b/src/commands/appdistribution-testers-add.ts @@ -5,8 +5,12 @@ import { AppDistributionClient } from "../appdistribution/client"; import { getEmails, getProjectName } from "../appdistribution/options-parser-util"; export const command = new Command("appdistribution:testers:add [emails...]") - .description("add testers to project") + .description("add testers to project (and possibly group)") .option("--file ", "a path to a file containing a list of tester emails to be added") + .option( + "--group-alias ", + "if specified, the testers are also added to the group identified by this alias" + ) .before(requireAuth) .action(async (emails: string[], options?: any) => { const projectName = await getProjectName(options); @@ -14,4 +18,11 @@ export const command = new Command("appdistribution:testers:add [emails...]") const emailsToAdd = getEmails(emails, options.file); utils.logBullet(`Adding ${emailsToAdd.length} testers to project`); await appDistroClient.addTesters(projectName, emailsToAdd); + if (options.groupAlias) { + utils.logBullet(`Adding ${emailsToAdd.length} testers to group`); + await appDistroClient.addTestersToGroup( + `${projectName}/groups/${options.groupAlias}`, + emailsToAdd + ); + } }); diff --git a/src/commands/appdistribution-testers-remove.ts b/src/commands/appdistribution-testers-remove.ts index 3ecbc1a29d7..c6bc972c8ea 100644 --- a/src/commands/appdistribution-testers-remove.ts +++ b/src/commands/appdistribution-testers-remove.ts @@ -7,25 +7,37 @@ import { getEmails, getProjectName } from "../appdistribution/options-parser-uti import { logger } from "../logger"; export const command = new Command("appdistribution:testers:remove [emails...]") - .description("remove testers from a project") + .description("remove testers from a project (or group)") .option("--file ", "a path to a file containing a list of tester emails to be removed") + .option( + "--group-alias ", + "if specified, the testers are only removed from the group identified by this alias, but not the project" + ) .before(requireAuth) .action(async (emails: string[], options?: any) => { const projectName = await getProjectName(options); const appDistroClient = new AppDistributionClient(); const emailsArr = getEmails(emails, options.file); - let deleteResponse; - try { - utils.logBullet(`Deleting ${emailsArr.length} testers from project`); - deleteResponse = await appDistroClient.removeTesters(projectName, emailsArr); - } catch (err: any) { - throw new FirebaseError(`Failed to remove testers ${err}`); - } + if (options.groupAlias) { + utils.logBullet(`Removing ${emailsArr.length} testers from group`); + await appDistroClient.removeTestersFromGroup( + `${projectName}/groups/${options.groupAlias}`, + emailsArr + ); + } else { + let deleteResponse; + try { + utils.logBullet(`Deleting ${emailsArr.length} testers from project`); + deleteResponse = await appDistroClient.removeTesters(projectName, emailsArr); + } catch (err: any) { + throw new FirebaseError(`Failed to remove testers ${err}`); + } - if (!deleteResponse.emails) { - utils.logSuccess(`Testers did not exist`); - return; + if (!deleteResponse.emails) { + utils.logSuccess(`Testers did not exist`); + return; + } + logger.debug(`Testers: ${deleteResponse.emails}, have been successfully deleted`); + utils.logSuccess(`${deleteResponse.emails.length} testers have successfully been deleted`); } - logger.debug(`Testers: ${deleteResponse.emails}, have been successfully deleted`); - utils.logSuccess(`${deleteResponse.emails.length} testers have successfully been deleted`); }); diff --git a/src/commands/index.ts b/src/commands/index.ts index 8d7de5c2362..1b3c5d3bc30 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -25,6 +25,9 @@ export function load(client: any): any { client.appdistribution.testers = {}; client.appdistribution.testers.add = loadCommand("appdistribution-testers-add"); client.appdistribution.testers.delete = loadCommand("appdistribution-testers-remove"); + client.appdistribution.group = {}; + client.appdistribution.group.create = loadCommand("appdistribution-group-create"); + client.appdistribution.group.delete = loadCommand("appdistribution-group-delete"); client.apps = {}; client.apps.create = loadCommand("apps-create"); client.apps.list = loadCommand("apps-list"); diff --git a/src/test/appdistro/client.spec.ts b/src/test/appdistro/client.spec.ts index 1390257cf46..db888a9f758 100644 --- a/src/test/appdistro/client.spec.ts +++ b/src/test/appdistro/client.spec.ts @@ -6,7 +6,11 @@ import * as rimraf from "rimraf"; import * as sinon from "sinon"; import * as tmp from "tmp"; -import { AppDistributionClient, BatchRemoveTestersResponse } from "../../appdistribution/client"; +import { + AppDistributionClient, + BatchRemoveTestersResponse, + Group, +} from "../../appdistribution/client"; import { appDistributionOrigin } from "../../api"; import { Distribution } from "../../appdistribution/distribution"; import { FirebaseError } from "../../error"; @@ -17,6 +21,7 @@ describe("distribution", () => { const tempdir = tmp.dirSync(); const projectName = "projects/123456789"; const appName = `${projectName}/apps/1:123456789:ios:abc123def456`; + const groupName = `${projectName}/groups/my-group`; const binaryFile = join(tempdir.name, "app.ipa"); fs.ensureFileSync(binaryFile); const mockDistribution = new Distribution(binaryFile); @@ -61,6 +66,7 @@ describe("distribution", () => { describe("deleteTesters", () => { const emails = ["a@foo.com", "b@foo.com"]; + const mockResponse: BatchRemoveTestersResponse = { emails: emails }; it("should throw error if delete fails", async () => { nock(appDistributionOrigin) @@ -73,7 +79,6 @@ describe("distribution", () => { expect(nock.isDone()).to.be.true; }); - const mockResponse: BatchRemoveTestersResponse = { emails: emails }; it("should resolve when request succeeds", async () => { nock(appDistributionOrigin) .post(`/v1/${projectName}/testers:batchRemove`) @@ -200,4 +205,99 @@ describe("distribution", () => { }); }); }); + + describe("createGroup", () => { + const mockResponse: Group = { name: groupName, displayName: "My Group" }; + + it("should throw error if request fails", async () => { + nock(appDistributionOrigin) + .post(`/v1/${projectName}/groups`) + .reply(400, { error: { status: "FAILED_PRECONDITION" } }); + await expect(appDistributionClient.createGroup(projectName, "My Group")).to.be.rejectedWith( + FirebaseError, + "Failed to create group" + ); + expect(nock.isDone()).to.be.true; + }); + + it("should resolve when request succeeds", async () => { + nock(appDistributionOrigin).post(`/v1/${projectName}/groups`).reply(200, mockResponse); + await expect( + appDistributionClient.createGroup(projectName, "My Group") + ).to.eventually.deep.eq(mockResponse); + expect(nock.isDone()).to.be.true; + }); + + it("should resolve when request with alias succeeds", async () => { + nock(appDistributionOrigin) + .post(`/v1/${projectName}/groups?groupId=my-group`) + .reply(200, mockResponse); + await expect( + appDistributionClient.createGroup(projectName, "My Group", "my-group") + ).to.eventually.deep.eq(mockResponse); + expect(nock.isDone()).to.be.true; + }); + }); + + describe("deleteGroup", () => { + it("should throw error if delete fails", async () => { + nock(appDistributionOrigin) + .delete(`/v1/${groupName}`) + .reply(400, { error: { status: "FAILED_PRECONDITION" } }); + await expect(appDistributionClient.deleteGroup(groupName)).to.be.rejectedWith( + FirebaseError, + "Failed to delete group" + ); + expect(nock.isDone()).to.be.true; + }); + + it("should resolve when request succeeds", async () => { + nock(appDistributionOrigin).delete(`/v1/${groupName}`).reply(200, {}); + await expect(appDistributionClient.deleteGroup(groupName)).to.be.eventually.fulfilled; + expect(nock.isDone()).to.be.true; + }); + }); + + describe("addTestersToGroup", () => { + const emails = ["a@foo.com", "b@foo.com"]; + + it("should throw error if request fails", async () => { + nock(appDistributionOrigin) + .post(`/v1/${groupName}:batchJoin`) + .reply(400, { error: { status: "FAILED_PRECONDITION" } }); + await expect(appDistributionClient.addTestersToGroup(groupName, emails)).to.be.rejectedWith( + FirebaseError, + "Failed to add testers to group" + ); + expect(nock.isDone()).to.be.true; + }); + + it("should resolve when request succeeds", async () => { + nock(appDistributionOrigin).post(`/v1/${groupName}:batchJoin`).reply(200, {}); + await expect(appDistributionClient.addTestersToGroup(groupName, emails)).to.be.eventually + .fulfilled; + expect(nock.isDone()).to.be.true; + }); + }); + + describe("removeTestersFromGroup", () => { + const emails = ["a@foo.com", "b@foo.com"]; + + it("should throw error if request fails", async () => { + nock(appDistributionOrigin) + .post(`/v1/${groupName}:batchLeave`) + .reply(400, { error: { status: "FAILED_PRECONDITION" } }); + await expect( + appDistributionClient.removeTestersFromGroup(groupName, emails) + ).to.be.rejectedWith(FirebaseError, "Failed to remove testers from group"); + expect(nock.isDone()).to.be.true; + }); + + it("should resolve when request succeeds", async () => { + nock(appDistributionOrigin).post(`/v1/${groupName}:batchLeave`).reply(200, {}); + await expect(appDistributionClient.removeTestersFromGroup(groupName, emails)).to.be.eventually + .fulfilled; + expect(nock.isDone()).to.be.true; + }); + }); }); From e989cada10e4ea57d8a27152212362b097ceda2a Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Thu, 15 Jun 2023 20:11:02 +0000 Subject: [PATCH 061/320] 12.4.0 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 44dd1fcdf1a..018218f8e08 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.3.1", + "version": "12.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.3.1", + "version": "12.4.0", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index 11f013e1d22..a93b3c2d71d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.3.1", + "version": "12.4.0", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From 3f3c1868ef5adce4cc9217fbe54c54ef31b01433 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Thu, 15 Jun 2023 20:11:15 +0000 Subject: [PATCH 062/320] [firebase-release] Removed change log and reset repo after 12.4.0 release --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd655c586b4..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +0,0 @@ -- Added `appdistribution:group:create` and - `appdistribution:group:delete`. -- Added `--group-alias` option to `appdistribution:testers:add` and - `appdistribution:testers:remove`. -- Fixed an issue where Storage rules could not be deployed to projects without a billing plan. (#5955) From 71c8e7d9ff43e17a0697cd66adf7ac52d7049de6 Mon Sep 17 00:00:00 2001 From: Leonardo Ortiz Date: Fri, 16 Jun 2023 12:26:08 -0300 Subject: [PATCH 063/320] Auth integration (#5667) * plugin integration WIP * add getInitFirebaseResponse type * satisfy tsconfig.compile.json * update get-init-firebase-response response format * isMonospaceEnv * set access token only in autoAuth * get monospace daemon port in function * create `.firebaserc` with authorized project * don't run setupMonospace if is vs code extension * return authorized project * isVSCE from options, return null if no project * clean up * use `projectRoot` again, only create rc if ... ... there's a project * lint friendly assertion * `/get-init-firebase-response` responses in logger * handle `userResponse` false * address nit, replace FIXME with TODO * depromisify isMonospaceEnv * remove unnecessary else * poll every 2 seconds instead of 5 --- src/monospace/index.ts | 17 ++++++++++------- src/monospace/interfaces.ts | 2 +- src/requireAuth.ts | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/monospace/index.ts b/src/monospace/index.ts index 410676cfdc4..b9d660127ed 100644 --- a/src/monospace/index.ts +++ b/src/monospace/index.ts @@ -10,7 +10,7 @@ import type { SetupMonospaceOptions, } from "./interfaces"; -const POLL_USER_RESPONSE_MILLIS = 5000; +const POLL_USER_RESPONSE_MILLIS = 2000; /** * Integrate Firebase Plugin with Monospace’s service Account Authentication @@ -54,9 +54,9 @@ async function pollAuthorizedProject(rid: string): Promise { if ("userResponse" in getInitFirebaseRes) { if (getInitFirebaseRes.userResponse.success) { return getInitFirebaseRes.userResponse.projectId; - } else { - return null; } + + return null; } const { error } = getInitFirebaseRes; @@ -72,7 +72,8 @@ async function pollAuthorizedProject(rid: string): Promise { return pollAuthorizedProject(rid); } - // FIXME: This is not being reached as the process exits before a new call is made + // TODO: Review this. It's not being reached as the process exits before a new + // call is made // Error response: User canceled without authorizing any project if (error === "USER_CANCELED") { @@ -81,7 +82,9 @@ async function pollAuthorizedProject(rid: string): Promise { throw new FirebaseError("User canceled without authorizing any project"); } - throw new FirebaseError(`Unhandled /get-init-firebase-response error: ${error}`); + throw new FirebaseError(`Unhandled /get-init-firebase-response error`, { + original: new Error(error), + }); } /** @@ -143,8 +146,8 @@ function createFirebaseRc(projectDir: string, authorizedProject: string): boolea /** * Whether this is a Monospace environment */ -export async function isMonospaceEnv(): Promise { - return Promise.resolve(Boolean(getMonospaceDaemonPort())); +export function isMonospaceEnv(): boolean { + return getMonospaceDaemonPort() !== undefined; } /** diff --git a/src/monospace/interfaces.ts b/src/monospace/interfaces.ts index d0bcd058d8b..c57bb4079e6 100644 --- a/src/monospace/interfaces.ts +++ b/src/monospace/interfaces.ts @@ -22,7 +22,7 @@ export type GetInitFirebaseResponse = } | { success: false; - error: "WAITING_FOR_RESPONSE" | "USER_CANCELED" | unknown; // TODO: define all errors + error: "WAITING_FOR_RESPONSE" | "USER_CANCELED" | string; // TODO: define all errors }; export type InitFirebaseResponse = diff --git a/src/requireAuth.ts b/src/requireAuth.ts index c86a8e43324..caaa985f96f 100644 --- a/src/requireAuth.ts +++ b/src/requireAuth.ts @@ -42,7 +42,7 @@ async function autoAuth(options: Options, authScopes: string[]): Promise { const token = await client.getAccessToken(); token !== null ? apiv2.setAccessToken(token) : false; - if (!options.isVSCE && (await isMonospaceEnv())) { + if (!options.isVSCE && isMonospaceEnv()) { await selectProjectInMonospace({ projectRoot: options.config.projectDir, project: options.project, From ba8a2a39b5baf11cc4b0c402de7273ac50c26276 Mon Sep 17 00:00:00 2001 From: joehan Date: Fri, 16 Jun 2023 12:15:18 -0700 Subject: [PATCH 064/320] Fix flaky convertConfig test (#5981) * Increasing timeout on flaking unit tests * take 2 * Increasing timeouts further * Found the actual cause - flaky tests were making remote calls and catching 403 errors * formats --- src/test/deploy/hosting/convertConfig.spec.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/test/deploy/hosting/convertConfig.spec.ts b/src/test/deploy/hosting/convertConfig.spec.ts index 35f45094b1c..46ce327e153 100644 --- a/src/test/deploy/hosting/convertConfig.spec.ts +++ b/src/test/deploy/hosting/convertConfig.spec.ts @@ -488,6 +488,20 @@ describe("convertConfig", () => { } describe("rewrites errors", () => { + let existingBackendStub: sinon.SinonStub; + + beforeEach(() => { + existingBackendStub = sinon + .stub(backend, "existingBackend") + .rejects( + new FirebaseError("Some permissions 403 error (that should be caught)", { status: 403 }) + ); + }); + + afterEach(() => { + existingBackendStub.restore(); + }); + it("should throw when rewrite points to function in the wrong region", async () => { await expect( convertConfig( @@ -520,7 +534,6 @@ describe("convertConfig", () => { ) ).to.eventually.be.rejectedWith(FirebaseError); }); - it("should throw when rewrite points to function being deleted", async () => { await expect( convertConfig( From 4b28e8a63604ac5b604a14d98c84b307646854fe Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Fri, 16 Jun 2023 13:03:39 -0700 Subject: [PATCH 065/320] Update plugin README (#5966) --- firebase-vscode/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/firebase-vscode/README.md b/firebase-vscode/README.md index 086212a4347..abaea3ca54f 100644 --- a/firebase-vscode/README.md +++ b/firebase-vscode/README.md @@ -6,8 +6,11 @@ This extension is in the development and exploration stage. 1. In order to make sure f5 launches the extension properly, first open your VS Code session from the `firebase-vscode` subdirectory (not the `firebase-tools` directory). -2. npm i -3. f5 to run opens new window +2. npm i (run this in both `firebase-tools` and `firebase-vscode`) +3. Make sure the extension `amodio.tsl-problem-matcher` is installed - this + enables the watcher to work, otherwise the Extension Development Host + will not automatically open on F5 when the compilation is done. +4. f5 to run opens new window f5 -> npm run watch defined in tasks.json My terminal didn't have npm available but yours might From 4612ef2fa0006dfab964acc51e7159974e3df490 Mon Sep 17 00:00:00 2001 From: christhompsongoogle <106194718+christhompsongoogle@users.noreply.github.com> Date: Fri, 16 Jun 2023 17:17:58 -0700 Subject: [PATCH 066/320] Emulators in the VSCode plugin (#5954) Add emulator support in the VSCode plugin. This is still a prototype version and you may encounter bugs. --- firebase-vscode/common/messaging/protocol.ts | 16 ++ firebase-vscode/common/messaging/types.d.ts | 18 ++ firebase-vscode/src/cli.ts | 37 ++- firebase-vscode/src/extension.ts | 8 +- firebase-vscode/src/options.ts | 9 +- firebase-vscode/src/workflow.ts | 55 +++- firebase-vscode/webviews/EmulatorPanel.tsx | 249 +++++++++++++++++++ firebase-vscode/webviews/SidebarApp.tsx | 17 +- src/config.ts | 2 +- src/emulator/commandUtils.ts | 12 +- src/emulator/controller.ts | 25 +- src/options.ts | 3 + 12 files changed, 418 insertions(+), 33 deletions(-) create mode 100644 firebase-vscode/webviews/EmulatorPanel.tsx diff --git a/firebase-vscode/common/messaging/protocol.ts b/firebase-vscode/common/messaging/protocol.ts index 087607fdfc4..c32f8f1c726 100644 --- a/firebase-vscode/common/messaging/protocol.ts +++ b/firebase-vscode/common/messaging/protocol.ts @@ -7,6 +7,7 @@ import { FirebaseConfig } from '../../../src/firebaseConfig'; import { FirebaseRC } from "../firebaserc"; import { User } from "../../../src/types/auth"; import { ServiceAccountUser } from "../types"; +import { EmulatorUiSelections, RunningEmulatorInfo } from "./types"; export interface WebviewToExtensionParamsMap { /** @@ -76,6 +77,18 @@ export interface WebviewToExtensionParamsMap { openLink: { href: string }; + + /** + * Equivalent to the `firebase emulators:start` command. + */ + launchEmulators : { + emulatorUiSelections: EmulatorUiSelections, + }; + + /** Stops the emulators gracefully allowing for data export if required. */ + stopEmulators: {}; + + selectEmulatorImportFolder: {}; } export interface ExtensionToWebviewParamsMap { @@ -117,6 +130,9 @@ export interface ExtensionToWebviewParamsMap { */ notifyFirebaseConfig: { firebaseJson: FirebaseConfig, firebaseRC: FirebaseRC }; + notifyEmulatorsStopped: {}; + notifyRunningEmulatorInfo: RunningEmulatorInfo ; + notifyEmulatorImportFolder: { folder: string }; } export type MessageParamsMap = WebviewToExtensionParamsMap | ExtensionToWebviewParamsMap; diff --git a/firebase-vscode/common/messaging/types.d.ts b/firebase-vscode/common/messaging/types.d.ts index cbae270f1c0..910b498eabe 100644 --- a/firebase-vscode/common/messaging/types.d.ts +++ b/firebase-vscode/common/messaging/types.d.ts @@ -1,4 +1,5 @@ import { Channel } from "../hosting/api"; +import { EmulatorInfo } from "../emulator/types"; import { ExtensionToWebviewParamsMap, MessageParamsMap } from "./protocol"; export interface Message { @@ -15,3 +16,20 @@ export interface MessageListeners { export interface ChannelWithId extends Channel { id: string; } + +/** + * Info to display in the UI while the emulators are running + */ +export interface RunningEmulatorInfo { + uiUrl: string; + displayInfo: EmulatorInfo[]; +} + +export interface EmulatorUiSelections { + projectId: string + firebaseJsonPath?: string + importStateFolderPath?: string + exportStateOnExit: boolean + mode: "hosting" | "all" + debugLogging: boolean +} diff --git a/firebase-vscode/src/cli.ts b/firebase-vscode/src/cli.ts index 87ab28f42e8..93fbab367a2 100644 --- a/firebase-vscode/src/cli.ts +++ b/firebase-vscode/src/cli.ts @@ -12,17 +12,22 @@ import { hostingChannelDeployAction } from "../../src/commands/hosting-channel-d import { listFirebaseProjects } from "../../src/management/projects"; import { requireAuth } from "../../src/requireAuth"; import { deploy } from "../../src/deploy"; -import { FirebaseConfig, HostingSingle } from "../../src/firebaseConfig"; -import { FirebaseRC } from "../common/firebaserc"; +import { FirebaseRC } from "../../src/firebaserc"; import { getDefaultHostingSite } from "../../src/getDefaultHostingSite"; import { initAction } from "../../src/commands/init"; +import { startAll as startAllEmulators, cleanShutdown as stopAllEmulators } from "../../src/emulator/controller"; +import { EmulatorRegistry } from "../../src/emulator/registry"; +import { EmulatorInfo, Emulators } from "../../src/emulator/types"; +import { FirebaseConfig, HostingSingle } from "../../src/firebaseConfig"; import { Account, User } from "../../src/types/auth"; import { Options } from "../../src/options"; import { currentOptions, getCommandOptions } from "./options"; import { setInquirerOptions } from "./stubs/inquirer-stub"; import { ServiceAccount } from "../common/types"; import { listChannels } from "../../src/hosting/api"; -import { ChannelWithId } from "../common/messaging/types"; +import { ChannelWithId } from "./messaging/types"; +import * as commandUtils from "../../src/emulator/commandUtils"; +import { EmulatorUiSelections } from "../common/messaging/types"; import { setEnabled } from "../../src/experiments"; import { pluginLogger } from "./logger-wrapper"; @@ -172,6 +177,32 @@ export async function initHosting(options: { spa: boolean; public: string }) { await initAction("hosting", commandOptions); } +export async function emulatorsStart(emulatorUiSelections: EmulatorUiSelections) { + const commandOptions = await getCommandOptions(undefined, { + ...currentOptions, + project: emulatorUiSelections.projectId, + exportOnExit: emulatorUiSelections.exportStateOnExit, + import: emulatorUiSelections.importStateFolderPath, + only: emulatorUiSelections.mode === "hosting" ? "hosting" : "" + }); + // Adjusts some options, export on exit can be a boolean or a path. + commandUtils.setExportOnExitOptions(commandOptions as commandUtils.ExportOnExitOptions); + return startAllEmulators(commandOptions, /*showUi=*/ true); +} + +export async function stopEmulators() { + await stopAllEmulators(); +} + +export function listRunningEmulators(): EmulatorInfo[] { + return EmulatorRegistry.listRunningWithInfo(); +} + +export function getEmulatorUiUrl(): string | undefined { + const url: URL = EmulatorRegistry.url(Emulators.UI); + return url.hostname === "unknown" ? undefined : url.toString(); +} + export async function deployToHosting( firebaseJSON: FirebaseConfig, firebaseRC: FirebaseRC, diff --git a/firebase-vscode/src/extension.ts b/firebase-vscode/src/extension.ts index 8dababb29a0..368fecf5afb 100644 --- a/firebase-vscode/src/extension.ts +++ b/firebase-vscode/src/extension.ts @@ -11,6 +11,7 @@ import { import { setupSidebar } from "./sidebar"; import { setupWorkflow } from "./workflow"; import { pluginLogger } from "./logger-wrapper"; +import { onShutdown } from "./workflow"; const broker = createBroker< ExtensionToWebviewParamsMap, @@ -26,5 +27,8 @@ export function activate(context: vscode.ExtensionContext) { setupSidebar(context, broker); } -// This method is called when your extension is deactivated -export function deactivate() {} +// This method is called when the extension is deactivated +export async function deactivate() { + // This await is optimistic but it might wait for a moment longer while we run cleanup activities + await onShutdown(); +} diff --git a/firebase-vscode/src/options.ts b/firebase-vscode/src/options.ts index b2734b44abb..a8d98372bcc 100644 --- a/firebase-vscode/src/options.ts +++ b/firebase-vscode/src/options.ts @@ -1,4 +1,3 @@ -import { Config as cliConfig } from "../../src/config"; import { FirebaseConfig } from "../../src/firebaseConfig"; import { FirebaseRC } from "../common/firebaserc"; import { RC } from "../../src/rc"; @@ -6,6 +5,7 @@ import { BaseOptions, Options } from "../../src/options"; import { Command } from "../../src/command"; import { ExtensionContext } from "vscode"; import { setInquirerOptions } from "./stubs/inquirer-stub"; +import * as commandUtils from "../../src/emulator/commandUtils"; /** * User-facing CLI options @@ -20,7 +20,8 @@ interface CliOptions extends Omit { * Final options passed to CLI command functions * Result of command.prepare() */ -interface CommandOptions extends Options {} +interface CommandOptions extends Options { +} /** * User-facing CLI options @@ -45,8 +46,10 @@ export let currentOptions: CliOptions & { isVSCE: boolean } = { nonInteractive: true, interactive: false, debug: false, - rc: null, + exportOnExit: false, + import: "", + isVSCE: true }; diff --git a/firebase-vscode/src/workflow.ts b/firebase-vscode/src/workflow.ts index fa799f6e64f..3d85312e2eb 100644 --- a/firebase-vscode/src/workflow.ts +++ b/firebase-vscode/src/workflow.ts @@ -11,12 +11,16 @@ import { writeFirebaseRCFile } from "./utils"; import { ExtensionBrokerImpl } from "./extension-broker"; import { deployToHosting, + emulatorsStart, getAccounts, + getChannels, + getEmulatorUiUrl, + initHosting, listProjects, + listRunningEmulators, login, logoutUser, - initHosting, - getChannels, + stopEmulators, } from "./cli"; import { User } from "../../src/types/auth"; import { FirebaseRC } from "../../src/firebaserc"; @@ -90,7 +94,7 @@ function updateCurrentUser( return currentUserEmail; } -function getRootFolders() { +function getRootFolders(): string[] { if (!workspace) { return []; } @@ -369,10 +373,53 @@ export function setupWorkflow( readAndSendFirebaseConfigs(broker); broker.send("notifyHostingFolderReady", { projectId, folderPath: currentOptions.cwd }); - + await fetchChannels(); } } + broker.on( + "launchEmulators", + async ({ emulatorUiSelections }) => { + await emulatorsStart(emulatorUiSelections); + broker.send("notifyRunningEmulatorInfo", { uiUrl: getEmulatorUiUrl(), displayInfo: listRunningEmulators() }); + } + ); + + broker.on( + "stopEmulators", + async () => { + await stopEmulators(); + // Update the UI + broker.send("notifyEmulatorsStopped"); + } + ); + + broker.on( + "selectEmulatorImportFolder", + async () => { + const options: vscode.OpenDialogOptions = { + canSelectMany: false, + openLabel: `Pick an import folder`, + title: `Pick an import folder`, + canSelectFiles: false, + canSelectFolders: true, + }; + const fileUri = await vscode.window.showOpenDialog(options); + // Update the UI of the selection + if (!fileUri || fileUri.length < 1) { + vscode.window.showErrorMessage("Invalid import folder selected."); + return; + } + broker.send("notifyEmulatorImportFolder", { folder: fileUri[0].fsPath }); + } + ); +} + +/** + * Cleans up any open resources before shutting down. + */ +export async function onShutdown() { + await stopEmulators(); } /** diff --git a/firebase-vscode/webviews/EmulatorPanel.tsx b/firebase-vscode/webviews/EmulatorPanel.tsx new file mode 100644 index 00000000000..a043bc66449 --- /dev/null +++ b/firebase-vscode/webviews/EmulatorPanel.tsx @@ -0,0 +1,249 @@ +import { + VSCodeButton, + VSCodeCheckbox, + VSCodeDivider, + VSCodeLink, + VSCodeProgressRing, + VSCodeTextField, +} from "@vscode/webview-ui-toolkit/react"; +import React, { useState } from "react"; +import { Spacer } from "./components/ui/Spacer"; +import { broker } from "./globals/html-broker"; +import { PanelSection } from "./components/ui/PanelSection"; +import { FirebaseConfig } from "../../src/firebaseConfig"; +import { + RunningEmulatorInfo, + EmulatorUiSelections, +} from "../common/messaging/types"; +import { VSCodeDropdown } from "@vscode/webview-ui-toolkit/react"; +import { VSCodeOption } from "@vscode/webview-ui-toolkit/react"; +import { EmulatorInfo } from "../../src/emulator/types"; +import { webLogger } from "./globals/web-logger"; + +const DEFAULT_EMULATOR_UI_SELECTIONS: EmulatorUiSelections = { + projectId: "demo-something", + importStateFolderPath: "", + exportStateOnExit: false, + mode: "all", + debugLogging: false, +}; + +/** + * Emulator panel component for the VSCode extension. Handles start/stop, import/export. + */ +export function EmulatorPanel({ + firebaseJson, +}: { + firebaseJson: FirebaseConfig; +}) { + if (!firebaseJson) { + throw Error("Expected a valid FirebaseConfig."); + } + const [emulatorUiSelections, setEmulatorUiSelections] = + useState(DEFAULT_EMULATOR_UI_SELECTIONS); + + webLogger.debug( + "initial state ui selections:" + JSON.stringify(emulatorUiSelections) + ); + function setEmulatorUiSelectionsAndSaveToWorkspace( + uiSelections: EmulatorUiSelections + ) { + // TODO(christhompson): Save UI selections in the current workspace. + // Requires context object. + setEmulatorUiSelections(uiSelections); + } + const [showEmulatorProgressIndicator, setShowEmulatorProgressIndicator] = + useState(false); + + // TODO(christhompson): Load UI selections from the current workspace. + // Requires context object. + // TODO(christhompson): Check if the emulators are running on extension start. + const [runningEmulatorInfo, setRunningEmulatorInfo] = + useState(); + + broker.on("notifyEmulatorsStopped", () => { + setShowEmulatorProgressIndicator(false); + webLogger.debug(`notifyEmulatorsStopped received in sidebar`); + setRunningEmulatorInfo(null); + }); + + broker.on("notifyRunningEmulatorInfo", (info: RunningEmulatorInfo) => { + setShowEmulatorProgressIndicator(false); + webLogger.debug(`notifyRunningEmulatorInfo received in sidebar`); + setRunningEmulatorInfo(info); + }); + + broker.on("notifyEmulatorImportFolder", ({ folder }) => { + webLogger.debug(`notifyEmulatorImportFolder received in sidebar: ${folder}`); + emulatorUiSelections.importStateFolderPath = folder; + setEmulatorUiSelectionsAndSaveToWorkspace({ ...emulatorUiSelections }); // rerender clone + }); + + function launchEmulators() { + if (!emulatorUiSelections.projectId) { + broker.send("showMessage", { + msg: "Missing project ID", + options: { + modal: true, + detail: `Please specify a project ID before starting the emulator suite.`, + }, + }); + return; + } + if (!firebaseJson) { + // TODO(christhompson): Consider using a default config in the case that + // firebase.json doesnt exist. + broker.send("showMessage", { + msg: "Missing firebase.json", + options: { + modal: true, + detail: `Unable to find firebase.json file.`, + }, + }); + return; + } + setShowEmulatorProgressIndicator(true); + broker.send("launchEmulators", { + emulatorUiSelections, + }); + } + + function stopEmulators() { + setShowEmulatorProgressIndicator(true); + broker.send("stopEmulators"); + } + + /** + * Called when import folder changes. + */ + function selectedImportFolder(event: any) { + event.preventDefault(); + broker.send("selectEmulatorImportFolder"); + } + + function toggleExportOnExit() { + const selections: EmulatorUiSelections = emulatorUiSelections; + selections.exportStateOnExit = !selections.exportStateOnExit; + webLogger.debug(`toggle export on exit : ${!selections.exportStateOnExit}`); + setEmulatorUiSelectionsAndSaveToWorkspace(selections); + } + + function projectIdChanged(event: React.ChangeEvent) { + webLogger.debug("projectIdChanged: " + event.target.value); + const selections: EmulatorUiSelections = emulatorUiSelections; + selections.projectId = event.target.value; + setEmulatorUiSelectionsAndSaveToWorkspace(selections); + } + + function emulatorModeChanged(event: React.ChangeEvent) { + webLogger.debug("emulatorModeChanged: " + event.target.value); + const selections: EmulatorUiSelections = emulatorUiSelections; + selections.mode = event.target.value as typeof emulatorUiSelections.mode; + setEmulatorUiSelectionsAndSaveToWorkspace(selections); + } + + function clearImportFolder() { + console.log(`clearImportFolder`); + emulatorUiSelections.importStateFolderPath = ""; + setEmulatorUiSelectionsAndSaveToWorkspace({ ...emulatorUiSelections }); + } + + // Make it pretty for the screen. Filter out the logging emulator since it's + // an implementation detail. + // TODO(christhompson): Add more info and sort this. + function formatEmulatorRunningInfo(emulatorInfos: EmulatorInfo[]): string { + return emulatorInfos + .map((info) => info.name) + .filter((name) => name !== "logging") + .join("
    "); + } + + return ( + +

    Launch the Emulator Suite

    + {/* TODO(christhompson): Insert some education links or tooltips here. */} + + Current project ID: + {/* TODO(christhompson): convert this into a demo- prefix checkbox or something. */} + projectIdChanged(event)} + > + + Import emulator state from directory: + + + selectedImportFolder(event)} + /> + + + Clear + + + toggleExportOnExit()} + > + Export emulator state on exit + + + {showEmulatorProgressIndicator ? : <>} + Emulator "mode" + emulatorModeChanged(event)} + > + All emulators + {!!firebaseJson.hosting && Only hosting} + + {runningEmulatorInfo ? ( + <> + + + The emulators are running. + + {!!runningEmulatorInfo.uiUrl && ( + + View them in the Emulator Suite UI + + )} + + Running Emulators: + +
    + + stopEmulators()}> + Click to stop the emulators + + + ) : ( + launchEmulators()} + disabled={showEmulatorProgressIndicator ? true : false} + > + Launch emulators + + )} +
    + ); +} diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx index fd6b3f59841..7b1bd1d1e17 100644 --- a/firebase-vscode/webviews/SidebarApp.tsx +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -4,13 +4,17 @@ import { Spacer } from "./components/ui/Spacer"; import { Body } from "./components/ui/Text"; import { broker } from "./globals/html-broker"; import { User } from "../../src/types/auth"; +import { FirebaseRC } from "../../src/firebaserc"; import { PanelSection } from "./components/ui/PanelSection"; import { AccountSection } from "./components/AccountSection"; import { ProjectSection } from "./components/ProjectSection"; +import { FirebaseConfig } from "../../src/firebaseConfig"; import { ServiceAccountUser } from "../common/types"; import { DeployPanel } from "./components/DeployPanel"; import { HostingState } from "./webview-types"; import { ChannelWithId } from "./messaging/types"; +import { EmulatorPanel } from "./EmulatorPanel"; + import { webLogger } from "./globals/web-logger"; export function SidebarApp() { @@ -28,6 +32,7 @@ export function SidebarApp() { ServiceAccountUser | User > | null>(null); const [isHostingOnboarded, setHostingOnboarded] = useState(false); + const [firebaseJson, setFirebaseJson] = useState(); useEffect(() => { webLogger.debug("loading SidebarApp component"); @@ -48,7 +53,14 @@ export function SidebarApp() { }); broker.on("notifyFirebaseConfig", ({ firebaseJson, firebaseRC }) => { - webLogger.debug("got firebase hosting", JSON.stringify(firebaseJson?.hosting)); + webLogger.debug( + "got firebase hosting", + JSON.stringify(firebaseJson?.hosting) + ); + if (firebaseJson) { + setFirebaseJson(firebaseJson); + webLogger.debug("set firebase JSON"); + } if (firebaseJson?.hosting) { webLogger.debug("Detected hosting setup"); setHostingOnboarded(true); @@ -99,7 +111,7 @@ export function SidebarApp() { email: userEmail!, // Safe to assume user email is already there singleAppSupport: true, }); - }; + } const accountSection = ( )} + {(!!userEmail && !!firebaseJson) && } ); } diff --git a/src/config.ts b/src/config.ts index 893392a87cd..85ed4fa4d92 100644 --- a/src/config.ts +++ b/src/config.ts @@ -238,7 +238,7 @@ export class Config { }); } - public static load(options: any, allowMissing?: boolean) { + public static load(options: any, allowMissing?: boolean): Config | null { const pd = detectProjectRoot(options); const filename = options.configPath || Config.FILENAME; if (pd) { diff --git a/src/emulator/commandUtils.ts b/src/emulator/commandUtils.ts index 888f1973609..c5bd1d73e2d 100644 --- a/src/emulator/commandUtils.ts +++ b/src/emulator/commandUtils.ts @@ -59,7 +59,7 @@ export const FLAG_TEST_PARAMS = "--test-params "; export const DESC_TEST_PARAMS = "A .env file containing test param values for your emulated extension."; -const DEFAULT_CONFIG = new Config( +export const DEFAULT_CONFIG = new Config( { eventarc: {}, database: {}, @@ -182,6 +182,11 @@ export function parseInspectionPort(options: any): number { return parsed; } +export interface ExportOnExitOptions { + exportOnExit?: boolean | string; + import?: string; +} + /** * Sets the correct export options based on --import and --export-on-exit. Mutates the options object. * Also validates if we have a correct setting we need to export the data on exit. @@ -190,10 +195,7 @@ export function parseInspectionPort(options: any): number { * export data the first time they start developing on a clean project. * @param options */ -export function setExportOnExitOptions(options: { - exportOnExit: boolean | string; - import?: string; -}): void { +export function setExportOnExitOptions(options: ExportOnExitOptions): void { if (options.exportOnExit || typeof options.exportOnExit === "string") { // note that options.exportOnExit may be a bool when used as a flag without a [dir] argument: // --import ./data --export-on-exit diff --git a/src/emulator/controller.ts b/src/emulator/controller.ts index 2a0d2da2eab..a837d5d2d7d 100644 --- a/src/emulator/controller.ts +++ b/src/emulator/controller.ts @@ -105,10 +105,9 @@ export async function cleanShutdown(): Promise { * Filters a list of emulators to only those specified in the config * @param options */ -export function filterEmulatorTargets(options: any): Emulators[] { +export function filterEmulatorTargets(options: { only: string; config: any }): Emulators[] { let targets = [...ALL_SERVICE_EMULATORS]; targets.push(Emulators.EXTENSIONS); - targets = targets.filter((e) => { return options.config.has(e) || options.config.has(`emulators.${e}`); }); @@ -318,7 +317,7 @@ export async function startAll( ); } else { // this should not work: - // firebase emulators:start --only doesnotexit + // firebase emulators:start --only doesnotexist throw new FirebaseError( `${name} is not a valid emulator name, valid options are: ${JSON.stringify( ALL_SERVICE_EMULATORS @@ -834,16 +833,6 @@ export async function startAll( await startEmulator(hostingEmulator); } - if (showUI && !shouldStart(options, Emulators.UI)) { - hubLogger.logLabeled( - "WARN", - "emulators", - "The Emulator UI is not starting, either because none of the emulated " + - "products have an interaction layer in Emulator UI or it cannot " + - "determine the Project ID. Pass the --project flag to specify a project." - ); - } - if (listenForEmulator.logging) { const loggingAddr = legacyGetFirstAddr(Emulators.LOGGING); const loggingEmulator = new LoggingEmulator({ @@ -854,6 +843,16 @@ export async function startAll( await startEmulator(loggingEmulator); } + if (showUI && !shouldStart(options, Emulators.UI)) { + hubLogger.logLabeled( + "WARN", + "emulators", + "The Emulator UI is not starting, either because none of the running " + + "emulators have a UI component or the Emulator UI cannot " + + "determine the Project ID. Pass the --project flag to specify a project." + ); + } + if (listenForEmulator.ui) { const ui = new EmulatorUI({ projectId: projectId, diff --git a/src/options.ts b/src/options.ts index bbf422c0fc2..45814867e0c 100644 --- a/src/options.ts +++ b/src/options.ts @@ -25,6 +25,9 @@ export interface BaseOptions { debug: boolean; rc: RC; + // Emulator specific import/export options + exportOnExit?: boolean | string; + import?: string; } export interface Options extends BaseOptions { From 17eb3212d39197f1190e07863ed8cf2a4da267cd Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Tue, 20 Jun 2023 11:22:06 -0700 Subject: [PATCH 067/320] Fixes to make web frameworks work for plugin (#6000) --- firebase-vscode/tsconfig.json | 2 +- firebase-vscode/webpack.prod.js | 13 +++++++++++-- src/dynamicImport.js | 12 +++++++++++- src/frameworks/constants.ts | 26 +------------------------- src/frameworks/index.ts | 2 +- src/frameworks/utils.ts | 15 +++++++++++++-- 6 files changed, 38 insertions(+), 32 deletions(-) diff --git a/firebase-vscode/tsconfig.json b/firebase-vscode/tsconfig.json index 1fff794824a..d13ff9f0c38 100644 --- a/firebase-vscode/tsconfig.json +++ b/firebase-vscode/tsconfig.json @@ -5,7 +5,7 @@ "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "typeRoots": ["node_modules/@types", "../src/types"], - "module": "ES2015", + "module": "es2020", "moduleResolution": "node", "target": "ES2020", "outDir": "dist", diff --git a/firebase-vscode/webpack.prod.js b/firebase-vscode/webpack.prod.js index e4bb4e4b10f..75a648edc85 100644 --- a/firebase-vscode/webpack.prod.js +++ b/firebase-vscode/webpack.prod.js @@ -1,7 +1,16 @@ const { merge } = require("webpack-merge"); +const TerserPlugin = require("terser-webpack-plugin"); const common = require("./webpack.common.js"); module.exports = common.map(config => merge(config, { - mode: "production" + mode: "production", + optimization: { + minimize: true, + minimizer: [new TerserPlugin({ + terserOptions: { + keep_classnames: /AbortSignal/, + keep_fnames: /AbortSignal/ + } + }), '...'] + } })); - diff --git a/src/dynamicImport.js b/src/dynamicImport.js index bad9d0d2b9c..8061b0a23ac 100644 --- a/src/dynamicImport.js +++ b/src/dynamicImport.js @@ -1,10 +1,20 @@ const { pathToFileURL } = require("url"); +// If being compiled with webpack, use non webpack require for these calls. +// (VSCode plugin uses webpack which by default replaces require calls +// with its own require, which doesn't work on files) +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment +const requireFunc = + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore prevent VSCE webpack from erroring on non_webpack_require + // eslint-disable-next-line camelcase + typeof __webpack_require__ === "function" ? __non_webpack_require__ : require; + exports.dynamicImport = function(mod) { if (mod.startsWith("file://")) return import(mod); if (mod.startsWith("/")) return import(pathToFileURL(mod).toString()); try { - const path = require.resolve(mod); + const path = requireFunc.resolve(mod); return import(pathToFileURL(path).toString()); } catch(e) { return Promise.reject(e); diff --git a/src/frameworks/constants.ts b/src/frameworks/constants.ts index 1b424cb187c..63cc6cd18b0 100644 --- a/src/frameworks/constants.ts +++ b/src/frameworks/constants.ts @@ -1,6 +1,4 @@ -import { readdirSync, statSync } from "fs"; -import { join } from "path"; -import { Framework, SupportLevel } from "./interfaces"; +import { SupportLevel } from "./interfaces"; import * as clc from "colorette"; export const NPM_COMMAND_TIMEOUT_MILLIES = 10_000; @@ -47,28 +45,6 @@ export const ALLOWED_SSR_REGIONS = [ export const I18N_ROOT = "/"; -export const WebFrameworks: Record = Object.fromEntries( - readdirSync(__dirname) - .filter((path) => statSync(join(__dirname, path)).isDirectory()) - .map((path) => { - // If not called by the CLI, (e.g., by the VS Code Extension) - // __dirname won't refer to this folder and these files won't be available. - // Instead it may find sibling folders that aren't modules, and this - // require will throw. - // Long term fix may be to bundle this instead of reading files at runtime - // but for now, this prevents crashing. - try { - return [path, require(join(__dirname, path))]; - } catch (e) { - return []; - } - }) - .filter( - ([, obj]) => - obj && obj.name && obj.discover && obj.build && obj.type !== undefined && obj.support - ) -); - export function GET_DEFAULT_BUILD_TARGETS() { return Promise.resolve(["production", "development"]); } diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index 42509442101..8ac1b3bf9c8 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -39,7 +39,6 @@ import { NODE_VERSION, SupportLevelWarnings, VALID_ENGINES, - WebFrameworks, } from "./constants"; import { BUILD_TARGET_PURPOSE, @@ -54,6 +53,7 @@ import { ensureTargeted } from "../functions/ensureTargeted"; import { isDeepStrictEqual } from "util"; import { resolveProjectPath } from "../projectPath"; import { logger } from "../logger"; +import { WebFrameworks } from "./frameworks"; export { WebFrameworks }; diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index 4c139fc9ab3..6967534c740 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -246,11 +246,22 @@ export function relativeRequire(dir: string, mod: "@nuxt/kit"): Promise; */ export function relativeRequire(dir: string, mod: string) { try { - const path = require.resolve(mod, { paths: [dir] }); + // If being compiled with webpack, use non webpack require for these calls. + // (VSCode plugin uses webpack which by default replaces require calls + // with its own require, which doesn't work on files) + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const requireFunc: typeof require = + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore prevent VSCE webpack from erroring on non_webpack_require + // eslint-disable-next-line camelcase + typeof __webpack_require__ === "function" ? __non_webpack_require__ : require; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore prevent VSCE webpack from erroring on non_webpack_require + const path = requireFunc.resolve(mod, { paths: [dir] }); if (extname(path) === ".mjs") { return dynamicImport(pathToFileURL(path).toString()); } else { - return require(path); + return requireFunc(path); } } catch (e) { const path = relative(process.cwd(), dir); From c552816e2c211326ba2b68123543719a5fa67cc7 Mon Sep 17 00:00:00 2001 From: blidd-google <112491344+blidd-google@users.noreply.github.com> Date: Tue, 20 Jun 2023 19:27:41 -0400 Subject: [PATCH 068/320] Run lifecycle hooks for specific codebases (#6011) * run lifecycle hooks for codebases specified by only * update changelog --- CHANGELOG.md | 1 + src/deploy/lifecycleHooks.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..20d9ab78675 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Run lifecycle hooks for specific codebases. (#6011) diff --git a/src/deploy/lifecycleHooks.ts b/src/deploy/lifecycleHooks.ts index 0c08e09a8cb..08851844a25 100644 --- a/src/deploy/lifecycleHooks.ts +++ b/src/deploy/lifecycleHooks.ts @@ -127,7 +127,6 @@ function getReleventConfigs(target: string, options: Options) { let onlyTargets = options.only.split(","); if (onlyTargets.includes(target)) { - // If the target matches entirely then all instances should be included. return targetConfigs; } @@ -140,6 +139,9 @@ function getReleventConfigs(target: string, options: Options) { }); return targetConfigs.filter((config: any) => { + if (target === "functions") { + return onlyTargets.includes(config.codebase); + } return !config.target || onlyTargets.includes(config.target); }); } From b1b513bcb534b63ad913eb54d743af1531b12a78 Mon Sep 17 00:00:00 2001 From: christhompsongoogle <106194718+christhompsongoogle@users.noreply.github.com> Date: Wed, 21 Jun 2023 13:00:33 -0700 Subject: [PATCH 069/320] Fixed a bug in the hosting config for emulators. (#6013) Also fixed an issue where an empty folder creates an issue loading the side panel. --- firebase-vscode/src/workflow.ts | 22 ++++++++----- firebase-vscode/webviews/EmulatorPanel.tsx | 36 +++++++++++++++++++--- firebase-vscode/webviews/SidebarApp.tsx | 3 +- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/firebase-vscode/src/workflow.ts b/firebase-vscode/src/workflow.ts index 3d85312e2eb..fd404affe06 100644 --- a/firebase-vscode/src/workflow.ts +++ b/firebase-vscode/src/workflow.ts @@ -145,12 +145,17 @@ export function setupWorkflow( ) { extensionContext = context; - // Get user-defined VSCode settings. - const workspaceConfig = workspace.getConfiguration( - 'firebase', - vscode.workspace.workspaceFolders[0].uri - ); - const shouldDebug: boolean = workspaceConfig.get('debug'); + var shouldDebug: boolean; + if (vscode.workspace.workspaceFolders) { + // Get user-defined VSCode settings. + const workspaceConfig = workspace.getConfiguration( + 'firebase', + vscode.workspace.workspaceFolders[0].uri + ); + shouldDebug = workspaceConfig.get('debug'); + } else { + shouldDebug = false; + } /** * Logging setup for logging to console and to file. @@ -158,13 +163,14 @@ export function setupWorkflow( // Sets up CLI logger to log to console process.env.DEBUG = 'true'; setupLoggers(); + + // Only log to file if firebase.debug extension setting is true. + if (shouldDebug) { // Re-implement file logger call from ../../src/bin/firebase.ts to not bring // in the entire firebase.ts file const rootFolders = getRootFolders(); const filePath = path.join(rootFolders[0], 'firebase-plugin-debug.log'); pluginLogger.info('Logging to path', filePath); - // Only log to file if firebase.debug extension setting is true. - if (shouldDebug) { logger.add( new transports.File({ level: "debug", diff --git a/firebase-vscode/webviews/EmulatorPanel.tsx b/firebase-vscode/webviews/EmulatorPanel.tsx index a043bc66449..3d35146a1a7 100644 --- a/firebase-vscode/webviews/EmulatorPanel.tsx +++ b/firebase-vscode/webviews/EmulatorPanel.tsx @@ -33,14 +33,20 @@ const DEFAULT_EMULATOR_UI_SELECTIONS: EmulatorUiSelections = { */ export function EmulatorPanel({ firebaseJson, + projectId, }: { firebaseJson: FirebaseConfig; + projectId?: string | undefined; }) { if (!firebaseJson) { throw Error("Expected a valid FirebaseConfig."); } + var defaultState = DEFAULT_EMULATOR_UI_SELECTIONS; + if (projectId) { + defaultState.projectId = getProjectIdForMode(projectId, defaultState.mode); + } const [emulatorUiSelections, setEmulatorUiSelections] = - useState(DEFAULT_EMULATOR_UI_SELECTIONS); + useState(defaultState); webLogger.debug( "initial state ui selections:" + JSON.stringify(emulatorUiSelections) @@ -74,7 +80,9 @@ export function EmulatorPanel({ }); broker.on("notifyEmulatorImportFolder", ({ folder }) => { - webLogger.debug(`notifyEmulatorImportFolder received in sidebar: ${folder}`); + webLogger.debug( + `notifyEmulatorImportFolder received in sidebar: ${folder}` + ); emulatorUiSelections.importStateFolderPath = folder; setEmulatorUiSelectionsAndSaveToWorkspace({ ...emulatorUiSelections }); // rerender clone }); @@ -139,7 +147,8 @@ export function EmulatorPanel({ webLogger.debug("emulatorModeChanged: " + event.target.value); const selections: EmulatorUiSelections = emulatorUiSelections; selections.mode = event.target.value as typeof emulatorUiSelections.mode; - setEmulatorUiSelectionsAndSaveToWorkspace(selections); + selections.projectId = getProjectIdForMode(projectId, selections.mode); + setEmulatorUiSelectionsAndSaveToWorkspace({...selections}); } function clearImportFolder() { @@ -208,7 +217,9 @@ export function EmulatorPanel({ onChange={(event) => emulatorModeChanged(event)} > All emulators - {!!firebaseJson.hosting && Only hosting} + {!!firebaseJson.hosting && ( + Only hosting + )} {runningEmulatorInfo ? ( <> @@ -247,3 +258,20 @@ export function EmulatorPanel({ ); } + +/** + * Formats a project ID with a demo prefix if we're in offline mode, or uses the + * regular ID if we're hosting. + */ +function getProjectIdForMode( + projectId: string | undefined, + mode: "all" | "hosting" +): string { + if (!projectId) { + return "demo-something"; + } + if (mode === "hosting") { + return projectId; + } + return "demo-" + projectId; +} \ No newline at end of file diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx index 7b1bd1d1e17..dfe0663244e 100644 --- a/firebase-vscode/webviews/SidebarApp.tsx +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -4,7 +4,6 @@ import { Spacer } from "./components/ui/Spacer"; import { Body } from "./components/ui/Text"; import { broker } from "./globals/html-broker"; import { User } from "../../src/types/auth"; -import { FirebaseRC } from "../../src/firebaserc"; import { PanelSection } from "./components/ui/PanelSection"; import { AccountSection } from "./components/AccountSection"; import { ProjectSection } from "./components/ProjectSection"; @@ -153,7 +152,7 @@ export function SidebarApp() { }} /> )} - {(!!userEmail && !!firebaseJson) && } + {(!!userEmail && !!firebaseJson) && } ); } From 0561d36b250fa7325029161f896cbc97335dbcce Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 21 Jun 2023 14:33:04 -0700 Subject: [PATCH 070/320] VSCode plugin refactoring and UX (#5968) --- firebase-vscode/.vscodeignore | 1 + firebase-vscode/common/firebaserc.ts | 2 - firebase-vscode/common/messaging/protocol.ts | 35 +- firebase-vscode/package-lock.json | 4 +- firebase-vscode/package.json | 26 +- firebase-vscode/src/cli.ts | 52 ++- firebase-vscode/src/config-files.ts | 146 ++++++++ firebase-vscode/src/logger-wrapper.ts | 2 +- firebase-vscode/src/options.ts | 53 +-- firebase-vscode/src/utils.ts | 11 - firebase-vscode/src/workflow.ts | 318 +++++++----------- firebase-vscode/webviews/SidebarApp.tsx | 39 +-- .../webviews/components/AccountSection.tsx | 31 +- .../webviews/components/DeployPanel.tsx | 147 ++++---- .../webviews/components/InitPanel.tsx | 48 +++ .../webviews/components/ProjectSection.tsx | 5 +- .../webviews/components/ui/SplitButton.scss | 38 +++ .../webviews/components/ui/SplitButton.tsx | 53 +++ .../components/ui/popup-menu/PopupMenu.tsx | 5 + firebase-vscode/webviews/globals/ux-text.ts | 22 ++ firebase-vscode/webviews/tsconfig.json | 2 +- firebase-vscode/webviews/webview-types.ts | 2 +- src/config.ts | 1 + src/deploy/hosting/prepare.ts | 17 +- src/detectProjectRoot.ts | 5 +- src/functionsConfig.ts | 4 +- src/management/projects.ts | 6 +- 27 files changed, 640 insertions(+), 435 deletions(-) delete mode 100644 firebase-vscode/common/firebaserc.ts create mode 100644 firebase-vscode/src/config-files.ts delete mode 100644 firebase-vscode/src/utils.ts create mode 100644 firebase-vscode/webviews/components/InitPanel.tsx create mode 100644 firebase-vscode/webviews/components/ui/SplitButton.scss create mode 100644 firebase-vscode/webviews/components/ui/SplitButton.tsx create mode 100644 firebase-vscode/webviews/globals/ux-text.ts diff --git a/firebase-vscode/.vscodeignore b/firebase-vscode/.vscodeignore index 091caca74cd..4dd9a138ef0 100644 --- a/firebase-vscode/.vscodeignore +++ b/firebase-vscode/.vscodeignore @@ -16,3 +16,4 @@ vsc-extension-quickstart.md webpack.*.js ../ *.zip +node_modules/ diff --git a/firebase-vscode/common/firebaserc.ts b/firebase-vscode/common/firebaserc.ts deleted file mode 100644 index 441be9895fa..00000000000 --- a/firebase-vscode/common/firebaserc.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { RCData } from '../../src/rc'; -export interface FirebaseRC extends Partial {} diff --git a/firebase-vscode/common/messaging/protocol.ts b/firebase-vscode/common/messaging/protocol.ts index c32f8f1c726..ec79deefe5e 100644 --- a/firebase-vscode/common/messaging/protocol.ts +++ b/firebase-vscode/common/messaging/protocol.ts @@ -4,20 +4,16 @@ */ import { FirebaseConfig } from '../../../src/firebaseConfig'; -import { FirebaseRC } from "../firebaserc"; import { User } from "../../../src/types/auth"; import { ServiceAccountUser } from "../types"; +import { RCData } from '../../../src/rc'; import { EmulatorUiSelections, RunningEmulatorInfo } from "./types"; export interface WebviewToExtensionParamsMap { /** - * Ask extension for env variables + * Ask extension for initial data */ - getEnv: {}; - /** - * User management - */ - getUsers: {}; + getInitialData: {}; addUser: {}; logout: { email: string }; @@ -36,11 +32,6 @@ export interface WebviewToExtensionParamsMap { singleAppSupport: boolean }; - /** - * Get hosting channels. - */ - getChannels: {}; - /** * Runs `firebase deploy` for hosting. * TODO(hsubox76): Generalize to work for all `firebase deploy` targets. @@ -50,16 +41,9 @@ export interface WebviewToExtensionParamsMap { }; /** - * Get currently selected Firebase project from extension runtime. + * Prompt user for text input */ - getSelectedProject: {}; - - /** - * Fetches the contents of the .firebaserc and firebase.json config files. - * If either or both files do not exist, then it will return a default - * value. - */ - getFirebaseJson: {}; + promptUserForInput: { title: string, prompt: string }; /** * Show a UI message using the vscode interface @@ -113,7 +97,7 @@ export interface ExtensionToWebviewParamsMap { * Notifies webview when user has successfully selected a hosting folder * and it has been written to firebase.json. */ - notifyHostingFolderReady: { projectId: string, folderPath: string }; + notifyHostingInitDone: { projectId: string, folderPath?: string }; /** * Notify webview of status of deployment attempt. @@ -128,7 +112,12 @@ export interface ExtensionToWebviewParamsMap { * Notify webview of initial discovery or change in firebase.json or * .firebaserc */ - notifyFirebaseConfig: { firebaseJson: FirebaseConfig, firebaseRC: FirebaseRC }; + notifyFirebaseConfig: { firebaseJson: FirebaseConfig, firebaseRC: RCData }; + + /** + * Return user-selected preview channel name + */ + notifyPreviewChannelResponse: { id: string }; notifyEmulatorsStopped: {}; notifyRunningEmulatorInfo: RunningEmulatorInfo ; diff --git a/firebase-vscode/package-lock.json b/firebase-vscode/package-lock.json index a08c836efd6..a9525311ad3 100644 --- a/firebase-vscode/package-lock.json +++ b/firebase-vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "firebase-vscode", - "version": "0.0.9", + "version": "0.0.22", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-vscode", - "version": "0.0.9", + "version": "0.0.22", "dependencies": { "@vscode/codicons": "0.0.30", "@vscode/webview-ui-toolkit": "^1.2.1", diff --git a/firebase-vscode/package.json b/firebase-vscode/package.json index 79a701a59d8..ad7369c27c9 100644 --- a/firebase-vscode/package.json +++ b/firebase-vscode/package.json @@ -3,7 +3,7 @@ "displayName": "firebase-vscode", "publisher": "firebase", "description": "VSCode Extension for Firebase", - "version": "0.0.9", + "version": "0.0.22-alpha.0", "engines": { "vscode": "^1.69.0" }, @@ -20,16 +20,26 @@ "configuration": { "title": "Firebase VS Code Extension", "properties": { - "firebase-vscode-extension.firebaseRcFolder": { + "firebase.debug": { + "type": "boolean", + "default": false, + "description": "Enable writing debug-level messages to the file provided in firebase.debugLogPath (requires restart)" + }, + "firebase.debugLogPath": { "type": "string", "default": "", - "description": "Firebase RC folder" + "description": "If firebase.debug is true, appends debug-level messages to the provided file (requires restart)" + }, + "firebase.npmPath": { + "type": "string", + "default": "", + "description": "Path to NPM executable in local environment" + }, + "firebase.useFrameworks": { + "type": "boolean", + "default": false, + "description": "Enable web frameworks in a local VSCode environment" } - }, - "firebase.debug": { - "type": "boolean", - "default": false, - "description": "Logs debug-level messages to firebase-plugin-debug.log (requires restart)" } }, "viewsContainers": { diff --git a/firebase-vscode/src/cli.ts b/firebase-vscode/src/cli.ts index 93fbab367a2..74d3a03f64b 100644 --- a/firebase-vscode/src/cli.ts +++ b/firebase-vscode/src/cli.ts @@ -12,24 +12,21 @@ import { hostingChannelDeployAction } from "../../src/commands/hosting-channel-d import { listFirebaseProjects } from "../../src/management/projects"; import { requireAuth } from "../../src/requireAuth"; import { deploy } from "../../src/deploy"; -import { FirebaseRC } from "../../src/firebaserc"; import { getDefaultHostingSite } from "../../src/getDefaultHostingSite"; import { initAction } from "../../src/commands/init"; import { startAll as startAllEmulators, cleanShutdown as stopAllEmulators } from "../../src/emulator/controller"; import { EmulatorRegistry } from "../../src/emulator/registry"; import { EmulatorInfo, Emulators } from "../../src/emulator/types"; -import { FirebaseConfig, HostingSingle } from "../../src/firebaseConfig"; import { Account, User } from "../../src/types/auth"; import { Options } from "../../src/options"; import { currentOptions, getCommandOptions } from "./options"; import { setInquirerOptions } from "./stubs/inquirer-stub"; import { ServiceAccount } from "../common/types"; import { listChannels } from "../../src/hosting/api"; -import { ChannelWithId } from "./messaging/types"; import * as commandUtils from "../../src/emulator/commandUtils"; -import { EmulatorUiSelections } from "../common/messaging/types"; -import { setEnabled } from "../../src/experiments"; +import { EmulatorUiSelections, ChannelWithId } from "../common/messaging/types"; import { pluginLogger } from "./logger-wrapper"; +import { Config } from "../../src/config"; /** * Wrap the CLI's requireAuth() which is normally run before every command @@ -39,6 +36,7 @@ import { pluginLogger } from "./logger-wrapper"; async function requireAuthWrapper(showError: boolean = true) { // Try to get global default from configstore. For some reason this is // often overwritten when restarting the extension. + pluginLogger.debug('requireAuthWrapper'); let account = getGlobalDefaultAccount(); if (!account) { // If nothing in configstore top level, grab the first "additionalAccount" @@ -48,8 +46,9 @@ async function requireAuthWrapper(showError: boolean = true) { setGlobalDefaultAccount(account); } } - // If account is still null, `requireAuth()` will use google-auth-library - // to look for the service account hopefully. + // `requireAuth()` will register the token with apiv2, and if account is + // still null at this point, it will use google-auth-library + // to find the service account. try { const commandOptions = await getCommandOptions(undefined, { ...currentOptions, @@ -71,8 +70,8 @@ async function requireAuthWrapper(showError: boolean = true) { } return false; } - // No accounts but no error on requireAuth means it's a service account - // (or glogin - edge case) + // If we reach here, there is either a google account or no error on + // requireAuth (which means there is a service account or glogin) return true; } @@ -91,7 +90,7 @@ export async function getAccounts(): Promise> { return accounts; } -export async function getChannels(firebaseJSON: FirebaseConfig): Promise { +export async function getChannels(firebaseJSON: Config): Promise { if (!firebaseJSON) { return []; } @@ -103,18 +102,14 @@ export async function getChannels(firebaseJSON: FirebaseConfig): Promise ({ ...channel, id: channel.name.split("/").pop() })); @@ -149,14 +144,13 @@ export async function listProjects() { return listFirebaseProjects(); } -export async function initHosting(options: { spa: boolean; public: string }) { +export async function initHosting( + options: { spa: boolean; public?: string, useFrameworks: boolean } +) { await requireAuthWrapper(); let webFrameworksOptions = {}; - if (process.env.MONOSPACE_ENV) { - pluginLogger.debug('initHosting found MONOSPACE_ENV, ' - + 'setting web frameworks options'); - // TODO(hsubox76): Also allow VS Code users to enable this manually with a UI - setEnabled('webframeworks', true); + if (options.useFrameworks) { + pluginLogger.debug('Setting web frameworks options'); webFrameworksOptions = { // Should use auto-discovered framework useDiscoveredFramework: true, @@ -187,7 +181,7 @@ export async function emulatorsStart(emulatorUiSelections: EmulatorUiSelections) }); // Adjusts some options, export on exit can be a boolean or a path. commandUtils.setExportOnExitOptions(commandOptions as commandUtils.ExportOnExitOptions); - return startAllEmulators(commandOptions, /*showUi=*/ true); + return startAllEmulators(commandOptions, /*showUi=*/ true); } export async function stopEmulators() { @@ -204,8 +198,7 @@ export function getEmulatorUiUrl(): string | undefined { } export async function deployToHosting( - firebaseJSON: FirebaseConfig, - firebaseRC: FirebaseRC, + firebaseJSON: Config, deployTarget: string ) { if (!(await requireAuthWrapper())) { @@ -216,11 +209,8 @@ export async function deployToHosting( try { const options = { ...currentOptions }; // TODO(hsubox76): handle multiple hosting configs - if (!(firebaseJSON.hosting as HostingSingle).site) { - pluginLogger.debug('Calling getDefaultHostingSite() with options', inspect(options)); - (firebaseJSON.hosting as HostingSingle).site = - await getDefaultHostingSite(options); - } + pluginLogger.debug('Calling getDefaultHostingSite() with options', inspect(options)); + firebaseJSON.set('hosting', { ...firebaseJSON.get('hosting'), site: await getDefaultHostingSite(options) }); pluginLogger.debug('Calling getCommandOptions() with options', inspect(options)); const commandOptions = await getCommandOptions(firebaseJSON, options); pluginLogger.debug('Calling hosting deploy with command options', inspect(commandOptions)); diff --git a/firebase-vscode/src/config-files.ts b/firebase-vscode/src/config-files.ts new file mode 100644 index 00000000000..888491cb06d --- /dev/null +++ b/firebase-vscode/src/config-files.ts @@ -0,0 +1,146 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as vscode from "vscode"; +import { workspace } from "vscode"; +import { ExtensionBrokerImpl } from "./extension-broker"; +import { updateOptions, currentOptions } from "./options"; +import { RC } from "../../src/rc"; +import { Config } from "../../src/config"; +import { pluginLogger } from "./logger-wrapper"; +import isEmpty from "lodash/isEmpty"; + +export function getRootFolders() { + if (!workspace) { + return []; + } + const folders = workspace.workspaceFolders + ? workspace.workspaceFolders.map((wf) => wf.uri.fsPath) + : []; + if (workspace.workspaceFile) { + folders.push(path.dirname(workspace.workspaceFile.fsPath)); + } + return Array.from(new Set(folders)); +} + +function getConfigPath(): string { + // Usually there's only one root folder unless someone is using a + // multi-root VS Code workspace. + // https://code.visualstudio.com/docs/editor/multi-root-workspaces + // We are trying to play it safe by assigning the cwd + // based on where a .firebaserc or firebase.json was found but if + // the user hasn't run firebase init there won't be one, and without + // a cwd we won't know where to put it. + const rootFolders = getRootFolders(); + for (const folder of rootFolders) { + if (fs.existsSync(path.join(folder, '.firebaserc')) + || fs.existsSync(path.join(folder, 'firebase.json'))) { + currentOptions.cwd = folder; + return folder; + } + } + currentOptions.cwd = rootFolders[0]; + return rootFolders[0]; +} + +/** + * Parse firebase.json and .firebaserc from the configured location, if they + * exist, and write to memory. + */ +export function readFirebaseConfigs(context: vscode.ExtensionContext) { + const configPath = getConfigPath(); + let firebaseRC: RC; + let firebaseJSON: Config; + try { + firebaseRC = RC.loadFile(path.join(configPath, '.firebaserc')); + } catch (e) { + pluginLogger.error(e.message); + throw e; + } + + // RC.loadFile doesn't throw if not found, it just returns an empty object + if (isEmpty(firebaseRC.data)) { + firebaseRC = null; + } + + try { + firebaseJSON = Config.load({ configPath: path.join(configPath, 'firebase.json') }); + } + catch (e) { + if (e.status === 404) { + firebaseJSON = null; + } else { + pluginLogger.error(e.message); + throw e; + } + } + updateOptions(context, firebaseJSON, firebaseRC); + return { firebaseJSON, firebaseRC }; + +} + +/** + * Read Firebase configs and then send it to webviews through the given broker + */ +export async function readAndSendFirebaseConfigs( + broker: ExtensionBrokerImpl, + context: vscode.ExtensionContext) { + const { firebaseJSON, firebaseRC } = readFirebaseConfigs(context); + broker.send("notifyFirebaseConfig", + { + firebaseJson: firebaseJSON?.data, firebaseRC: firebaseRC?.data + }); +} + +/** + * Write new default project to .firebaserc + */ +export async function updateFirebaseRCProject( + context: vscode.ExtensionContext, + alias: string, + projectId: string +) { + if (!currentOptions.rc) { + if (!currentOptions.cwd) { + currentOptions.cwd = getConfigPath(); + } + currentOptions.rc = new RC(path.join(currentOptions.cwd, ".firebaserc"), + {}); + } + currentOptions.rc.addProjectAlias(alias, projectId); + currentOptions.rc.save(); + updateOptions(context, undefined, currentOptions.rc); +} + +/** + * Set up a FileSystemWatcher for .firebaserc and firebase.json Also un-watch and re-watch when the + * configuration for where in the workspace the .firebaserc and firebase.json are. + */ +export function setupFirebaseJsonAndRcFileSystemWatcher( + broker: ExtensionBrokerImpl, + context: vscode.ExtensionContext +): vscode.Disposable { + // Create a new watcher + let watcher = newWatcher(); + + // Return a disposable that tears down a watcher if it's active + return { + dispose() { + watcher && watcher.dispose(); + }, + }; + + // HelperFunction to create a new watcher + function newWatcher() { + if (!currentOptions.cwd) { + return null; + } + + let watcher = workspace.createFileSystemWatcher( + path.join(currentOptions.cwd, "{firebase.json,.firebaserc}") + ); + watcher.onDidChange(async () => { + readAndSendFirebaseConfigs(broker, context); + }); + return watcher; + } +} diff --git a/firebase-vscode/src/logger-wrapper.ts b/firebase-vscode/src/logger-wrapper.ts index 40e9d9a0667..f736403f32a 100644 --- a/firebase-vscode/src/logger-wrapper.ts +++ b/firebase-vscode/src/logger-wrapper.ts @@ -12,4 +12,4 @@ for (const logLevel of logLevels) { }; } -setInquirerLogger(pluginLogger); \ No newline at end of file +setInquirerLogger(pluginLogger); diff --git a/firebase-vscode/src/options.ts b/firebase-vscode/src/options.ts index a8d98372bcc..a327a5bfd86 100644 --- a/firebase-vscode/src/options.ts +++ b/firebase-vscode/src/options.ts @@ -1,37 +1,19 @@ -import { FirebaseConfig } from "../../src/firebaseConfig"; -import { FirebaseRC } from "../common/firebaserc"; import { RC } from "../../src/rc"; -import { BaseOptions, Options } from "../../src/options"; +import { Options } from "../../src/options"; import { Command } from "../../src/command"; import { ExtensionContext } from "vscode"; import { setInquirerOptions } from "./stubs/inquirer-stub"; -import * as commandUtils from "../../src/emulator/commandUtils"; +import { Config } from "../../src/config"; /** * User-facing CLI options - * Passed to command.prepare() */ - -interface CliOptions extends Omit { - config: string; -} - -/** - * Final options passed to CLI command functions - * Result of command.prepare() - */ -interface CommandOptions extends Options { -} - -/** - * User-facing CLI options - */ -export let currentOptions: CliOptions & { isVSCE: boolean } = { +export let currentOptions: Options & { isVSCE: boolean } = { cwd: "", configPath: "", only: "", except: "", - config: "", + config: new Config({}), filteredTargets: [], force: true, @@ -55,24 +37,23 @@ export let currentOptions: CliOptions & { isVSCE: boolean } = { export function updateOptions( context: ExtensionContext, - firebaseJSON: FirebaseConfig, - firebaseRC: FirebaseRC + firebaseJSON: Config, + firebaseRC: RC ) { - // const config = new cliConfig(firebaseJSON, options); - // currentOptions.config = config; if (firebaseJSON) { + currentOptions.config = firebaseJSON; currentOptions.configPath = `${currentOptions.cwd}/firebase.json`; - if (firebaseJSON.hosting) { + if (firebaseJSON.has('hosting')) { currentOptions = { ...currentOptions, - ...firebaseJSON.hosting, + ...firebaseJSON.get('hosting'), }; } } else { currentOptions.configPath = ""; } if (firebaseRC) { - currentOptions.rc = new RC(`${currentOptions.cwd}/.firebaserc`, firebaseRC); + currentOptions.rc = firebaseRC; currentOptions.project = firebaseRC.projects?.default; } else { currentOptions.rc = null; @@ -88,15 +69,15 @@ export function updateOptions( * Mostly runs it through the CLI's command.prepare() options formatter. */ export async function getCommandOptions( - firebaseJSON: FirebaseConfig = {}, - options: CliOptions = currentOptions -): Promise { + firebaseJSON: Config, + options: Options = currentOptions +): Promise { // Use any string, it doesn't affect `prepare()`. const command = new Command("deploy"); - let newOptions = Object.assign(options); - if (firebaseJSON.hosting) { - newOptions = Object.assign(newOptions, firebaseJSON.hosting); + let newOptions = Object.assign(options, { config: options.configPath }); + if (firebaseJSON?.has('hosting')) { + newOptions = Object.assign(newOptions, firebaseJSON.get('hosting')); } await command.prepare(newOptions); - return newOptions as CommandOptions; + return newOptions as Options; } diff --git a/firebase-vscode/src/utils.ts b/firebase-vscode/src/utils.ts deleted file mode 100644 index e7a95b8d01a..00000000000 --- a/firebase-vscode/src/utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as fs from "fs"; -import { FirebaseRC } from "../../src/firebaserc"; - -// TODO(hsubox76): use `loadRC` and `RC.save` from firebase-tools src/rc.ts -// for RC file operations -export async function writeFirebaseRCFile( - filename: string, - content: FirebaseRC -) { - fs.writeFileSync(filename, JSON.stringify(content, null, 2)); -} diff --git a/firebase-vscode/src/workflow.ts b/firebase-vscode/src/workflow.ts index fd404affe06..ce23f0b23d1 100644 --- a/firebase-vscode/src/workflow.ts +++ b/firebase-vscode/src/workflow.ts @@ -1,5 +1,4 @@ import * as path from "path"; -import * as fs from "fs"; import * as vscode from "vscode"; import { transports, format } from "winston"; import stripAnsi from "strip-ansi"; @@ -7,7 +6,6 @@ import { SPLAT } from "triple-beam"; import { ExtensionContext, workspace } from "vscode"; import { FirebaseProjectMetadata } from "../../src/types/project"; -import { writeFirebaseRCFile } from "./utils"; import { ExtensionBrokerImpl } from "./extension-broker"; import { deployToHosting, @@ -23,22 +21,26 @@ import { stopEmulators, } from "./cli"; import { User } from "../../src/types/auth"; -import { FirebaseRC } from "../../src/firebaserc"; -import { FirebaseConfig } from "../../src/firebaseConfig"; -import { currentOptions, updateOptions } from "./options"; -import { ServiceAccountUser } from "./types"; +import { currentOptions } from "./options"; import { selectProjectInMonospace } from "../../src/monospace"; import { setupLoggers, tryStringify } from "../../src/utils"; import { pluginLogger } from "./logger-wrapper"; import { logger } from '../../src/logger'; +import { discover } from "../../src/frameworks"; +import { setEnabled } from "../../src/experiments"; +import { + readAndSendFirebaseConfigs, + setupFirebaseJsonAndRcFileSystemWatcher, + updateFirebaseRCProject, + getRootFolders +} from "./config-files"; +import { ServiceAccountUser } from "../common/types"; -let firebaseRC: FirebaseRC | null = null; -let firebaseJSON: FirebaseConfig | null = null; -let extensionContext: ExtensionContext = null; let users: Array = []; let currentUserEmail = ""; // Stores a mapping from user email to list of projects for that user let projectsUserMapping = new Map(); +let channels = null; async function fetchUsers() { const accounts = await getAccounts(); @@ -49,7 +51,6 @@ async function fetchUsers() { * Get the user to select a project. */ async function promptUserForProject( - broker: ExtensionBrokerImpl, projects: FirebaseProjectMetadata[] ) { const items = projects.map(({ projectId }) => projectId); @@ -58,7 +59,7 @@ async function promptUserForProject( vscode.window.showQuickPick(items).then(async (projectId) => { const project = projects.find((p) => p.projectId === projectId); if (!project) { - if (firebaseRC?.projects?.default) { + if (currentOptions.rc?.projects?.default) { // Don't show an error message if a project was previously selected, // just do nothing. resolve(null); @@ -94,69 +95,33 @@ function updateCurrentUser( return currentUserEmail; } -function getRootFolders(): string[] { - if (!workspace) { - return []; - } - const folders = workspace.workspaceFolders - ? workspace.workspaceFolders.map((wf) => wf.uri.fsPath) - : []; - if (workspace.workspaceFile) { - folders.push(path.dirname(workspace.workspaceFile.fsPath)); - } - return Array.from(new Set(folders)); -} - -function getConfigFile(filename: string): T | null { - const rootFolders = getRootFolders(); - for (const folder of rootFolders) { - const jsonFilePath = path.join(folder, filename); - if (fs.existsSync(jsonFilePath)) { - const fileText = fs.readFileSync(jsonFilePath, "utf-8"); - try { - const result = JSON.parse(fileText); - currentOptions.cwd = folder; - return result; - } catch (e) { - pluginLogger.error(`Error parsing JSON in ${jsonFilePath}`); - return null; - } - } - } - // Usually there's only one root folder unless someone is using a - // multi-root VS Code workspace. - // https://code.visualstudio.com/docs/editor/multi-root-workspaces - // We were trying to play it safe up above by assigning the cwd - // based on where a .firebaserc or firebase.json was found but if - // the user hasn't run firebase init there won't be one, and without - // a cwd we won't know where to put it. - // - // TODO: prompt where we're going to save a new firebase config - // file before we do it so the user can change it - if (!currentOptions.cwd) { - currentOptions.cwd = rootFolders[0]; - } - return null; -} - -export function setupWorkflow( +export async function setupWorkflow( context: ExtensionContext, broker: ExtensionBrokerImpl ) { - extensionContext = context; - var shouldDebug: boolean; + // Get user-defined VSCode settings if workspace is found. + let shouldWriteDebug: boolean = false; + let debugLogPath: string = ''; + let useFrameworks: boolean = false; + let npmPath: string = ''; if (vscode.workspace.workspaceFolders) { - // Get user-defined VSCode settings. const workspaceConfig = workspace.getConfiguration( 'firebase', vscode.workspace.workspaceFolders[0].uri ); - shouldDebug = workspaceConfig.get('debug'); - } else { - shouldDebug = false; + shouldWriteDebug = workspaceConfig.get('debug'); + debugLogPath= workspaceConfig.get('debugLogPath'); + useFrameworks = workspaceConfig.get('useFrameworks'); + npmPath = workspaceConfig.get('npmPath'); + if (npmPath) { + process.env.PATH += `:${npmPath}`; + } } + if (useFrameworks) { + setEnabled('webframeworks', true); + } /** * Logging setup for logging to console and to file. */ @@ -165,30 +130,24 @@ export function setupWorkflow( setupLoggers(); // Only log to file if firebase.debug extension setting is true. - if (shouldDebug) { - // Re-implement file logger call from ../../src/bin/firebase.ts to not bring - // in the entire firebase.ts file - const rootFolders = getRootFolders(); - const filePath = path.join(rootFolders[0], 'firebase-plugin-debug.log'); - pluginLogger.info('Logging to path', filePath); - logger.add( - new transports.File({ - level: "debug", - filename: filePath, - format: format.printf((info) => { - const segments = [info.message, ...(info[SPLAT] || [])] - .map(tryStringify); - return `[${info.level}] ${stripAnsi(segments.join(" "))}`; - }), - }) - ); - } - // Read config files and store in memory. - readFirebaseConfigs(); - // Check current users state - fetchUsers(); - // Get hosting channels - fetchChannels(); + if (shouldWriteDebug) { + // Re-implement file logger call from ../../src/bin/firebase.ts to not bring + // in the entire firebase.ts file + const rootFolders = getRootFolders(); + const filePath = debugLogPath || path.join(rootFolders[0], 'firebase-plugin-debug.log'); + pluginLogger.info('Logging to path', filePath); + logger.add( + new transports.File({ + level: "debug", + filename: filePath, + format: format.printf((info) => { + const segments = [info.message, ...(info[SPLAT] || [])] + .map(tryStringify); + return `[${info.level}] ${stripAnsi(segments.join(" "))}`; + }), + }) + ); + } /** * Call pluginLogger with log arguments received from webview. @@ -197,7 +156,8 @@ export function setupWorkflow( pluginLogger[level]('(Webview)', ...args); }); - broker.on("getEnv", async () => { + broker.on("getInitialData", async () => { + // Env pluginLogger.debug(`Value of process.env.MONOSPACE_ENV: ` + `${process.env.MONOSPACE_ENV}`); broker.send("notifyEnv", { @@ -205,14 +165,24 @@ export function setupWorkflow( isMonospace: Boolean(process.env.MONOSPACE_ENV), } }); - }); - broker.on("getUsers", async () => { - if (users.length === 0) { - await fetchUsers(); - } + // Firebase JSON and RC + readAndSendFirebaseConfigs(broker, context); + + // User login state + await fetchUsers(); broker.send("notifyUsers", { users }); currentUserEmail = updateCurrentUser(users, broker); + if (users.length > 0) { + await fetchChannels(); + } + + // Project + if (currentOptions.rc?.projects?.default) { + broker.send("notifyProjectChanged", { + projectId: currentOptions.rc.projects.default + }); + } }); broker.on("logout", async ({ email }: { email: string }) => { @@ -227,16 +197,6 @@ export function setupWorkflow( } }); - broker.on("getSelectedProject", async () => { - // For now, just read the cached value. - // TODO: Extend this to reading from firebaserc - if (firebaseRC?.projects?.default) { - broker.send("notifyProjectChanged", - { projectId: firebaseRC?.projects?.default }); - } - fetchChannels(); - }); - broker.on("showMessage", async ({ msg, options }) => { vscode.window.showInformationMessage(msg, options); }); @@ -274,26 +234,32 @@ export function setupWorkflow( broker.on("hostingDeploy", async ({ target: deployTarget }) => { const { success, consoleUrl, hostingUrl } = await deployToHosting( - firebaseJSON, - firebaseRC, + currentOptions.config, deployTarget ); broker.send("notifyHostingDeploy", { success, consoleUrl, hostingUrl }); if (success) { - fetchChannels(); + fetchChannels(true); } }); - broker.on("getFirebaseJson", async () => { - readAndSendFirebaseConfigs(broker); + broker.on("promptUserForInput", async () => { + const response = await vscode.window.showInputBox({ + title: "New Preview Channel", + prompt: "Enter a name for the new preview channel" + }); + broker.send("notifyPreviewChannelResponse", { id: response }); }); context.subscriptions.push( - setupFirebaseJsonAndRcFileSystemWatcher(broker) + setupFirebaseJsonAndRcFileSystemWatcher(broker, context) ); - async function fetchChannels() { - const channels = await getChannels(firebaseJSON); + async function fetchChannels(force = false) { + if (force || !channels) { + pluginLogger.debug('Fetching hosting channels'); + channels = await getChannels(currentOptions.config); + }; broker.send("notifyChannels", { channels }); } @@ -347,41 +313,56 @@ export function setupWorkflow( projectsUserMapping.set(email, projects); } try { - projectId = await promptUserForProject(broker, projects); + projectId = await promptUserForProject(projects); } catch (e) { vscode.window.showErrorMessage(e.message); } } if (projectId) { - await updateFirebaseRC("default", projectId); + await updateFirebaseRCProject(context, "default", projectId); broker.send("notifyProjectChanged", { projectId }); - fetchChannels(); + fetchChannels(true); } } async function selectAndInitHosting({ projectId, singleAppSupport }) { - const options: vscode.OpenDialogOptions = { - canSelectMany: false, - openLabel: `Select distribution/public folder for ${projectId}`, - canSelectFiles: false, - canSelectFolders: true, - }; - const fileUri = await vscode.window.showOpenDialog(options); - if (fileUri && fileUri[0] && fileUri[0].fsPath) { - const publicFolderFull = fileUri[0].fsPath; - const publicFolder = publicFolderFull.substring( - currentOptions.cwd.length + 1 - ); + let discoveredFramework; + // Note: discover() takes a few seconds. No need to block users that don't + // have frameworks support enabled. + if (useFrameworks) { + discoveredFramework = useFrameworks && await discover(currentOptions.cwd, false); + pluginLogger.debug('Searching for a web framework in this project.'); + } + if (discoveredFramework) { + pluginLogger.debug('Detected web framework, launching frameworks init.'); await initHosting({ spa: singleAppSupport, - public: publicFolder, + useFrameworks: true }); - readAndSendFirebaseConfigs(broker); - broker.send("notifyHostingFolderReady", - { projectId, folderPath: currentOptions.cwd }); - - await fetchChannels(); + } else { + const options: vscode.OpenDialogOptions = { + canSelectMany: false, + openLabel: `Select distribution/public folder for ${projectId}`, + canSelectFiles: false, + canSelectFolders: true, + }; + const fileUri = await vscode.window.showOpenDialog(options); + if (fileUri && fileUri[0] && fileUri[0].fsPath) { + const publicFolderFull = fileUri[0].fsPath; + const publicFolder = publicFolderFull.substring( + currentOptions.cwd.length + 1 + ); + await initHosting({ + spa: singleAppSupport, + public: publicFolder, + useFrameworks: false + }); + } } + readAndSendFirebaseConfigs(broker, context); + broker.send("notifyHostingInitDone", + { projectId, folderPath: currentOptions.cwd }); + await fetchChannels(true); } broker.on( "launchEmulators", @@ -427,76 +408,3 @@ export function setupWorkflow( export async function onShutdown() { await stopEmulators(); } - -/** - * Parse firebase.json and .firebaserc from the configured location, if they - * exist, and write to memory. - */ -function readFirebaseConfigs() { - firebaseRC = getConfigFile(".firebaserc"); - firebaseJSON = getConfigFile("firebase.json"); - - updateOptions(extensionContext, firebaseJSON, firebaseRC); -} - -/** - * Read Firebase configs and then send it to webviews through the given broker - */ -async function readAndSendFirebaseConfigs(broker: ExtensionBrokerImpl) { - readFirebaseConfigs(); - broker.send("notifyFirebaseConfig", - { - firebaseJson: firebaseJSON, firebaseRC - }); -} - -/** - * Write new default project to .firebaserc - */ -async function updateFirebaseRC(alias: string, projectId: string) { - if (currentOptions.cwd) { - firebaseRC = { - ...firebaseRC, - projects: { - default: firebaseRC?.projects?.default || "", - ...(firebaseRC?.projects || {}), - [alias]: projectId, - }, - }; - writeFirebaseRCFile(`${currentOptions.cwd}/.firebaserc`, firebaseRC); - updateOptions(extensionContext, firebaseJSON, firebaseRC); - } -} - -/** - * Set up a FileSystemWatcher for .firebaserc and firebase.json Also un-watch and re-watch when the - * configuration for where in the workspace the .firebaserc and firebase.json are. - */ -function setupFirebaseJsonAndRcFileSystemWatcher( - broker: ExtensionBrokerImpl -): vscode.Disposable { - // Create a new watcher - let watcher = newWatcher(); - - // Return a disposable that tears down a watcher if it's active - return { - dispose() { - watcher && watcher.dispose(); - }, - }; - - // HelperFunction to create a new watcher - function newWatcher() { - if (!currentOptions.cwd) { - return null; - } - - let watcher = workspace.createFileSystemWatcher( - path.join(currentOptions.cwd, "{firebase.json,.firebaserc}") - ); - watcher.onDidChange(async () => { - readAndSendFirebaseConfigs(broker); - }); - return watcher; - } -} diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx index dfe0663244e..86a9ef0a3f6 100644 --- a/firebase-vscode/webviews/SidebarApp.tsx +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -1,10 +1,7 @@ -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; import React, { useEffect, useState } from "react"; import { Spacer } from "./components/ui/Spacer"; -import { Body } from "./components/ui/Text"; import { broker } from "./globals/html-broker"; import { User } from "../../src/types/auth"; -import { PanelSection } from "./components/ui/PanelSection"; import { AccountSection } from "./components/AccountSection"; import { ProjectSection } from "./components/ProjectSection"; import { FirebaseConfig } from "../../src/firebaseConfig"; @@ -15,6 +12,7 @@ import { ChannelWithId } from "./messaging/types"; import { EmulatorPanel } from "./EmulatorPanel"; import { webLogger } from "./globals/web-logger"; +import { InitFirebasePanel } from "./components/InitPanel"; export function SidebarApp() { const [projectId, setProjectId] = useState(null); @@ -35,19 +33,15 @@ export function SidebarApp() { useEffect(() => { webLogger.debug("loading SidebarApp component"); - broker.send("getEnv"); - broker.send("getUsers"); - broker.send("getFirebaseJson"); - broker.send("getSelectedProject"); - broker.send("getChannels"); + broker.send("getInitialData"); broker.on("notifyEnv", ({ env }) => { - webLogger.debug("notifyEnv()"); + webLogger.debug(`notifyEnv() returned ${JSON.stringify(env)}`); setEnv(env); }); broker.on("notifyChannels", ({ channels }) => { - webLogger.debug("notifyChannels()"); + webLogger.debug(`notifyChannels() returned ${JSON.stringify(channels)}`); setChannels(channels); }); @@ -61,7 +55,7 @@ export function SidebarApp() { webLogger.debug("set firebase JSON"); } if (firebaseJson?.hosting) { - webLogger.debug("Detected hosting setup"); + webLogger.debug("Detected firebase.json"); setHostingOnboarded(true); broker.send("showMessage", { msg: "Auto-detected hosting setup in this folder", @@ -79,7 +73,7 @@ export function SidebarApp() { }); broker.on("notifyUsers", ({ users }) => { - webLogger.debug("notifyUsers()"); + webLogger.debug(`notifyUsers() returned ${JSON.stringify(users)}`); setAllUsers(users); }); @@ -93,14 +87,14 @@ export function SidebarApp() { setUserEmail(email); }); - broker.on("notifyHostingFolderReady", ({ projectId, folderPath }) => { - webLogger.debug(`notifyHostingFolderReady: ${projectId}, ${folderPath}`); + broker.on("notifyHostingInitDone", ({ projectId, folderPath }) => { + webLogger.debug(`notifyHostingInitDone: ${projectId}, ${folderPath}`); setHostingOnboarded(true); }); broker.on("notifyHostingDeploy", ({ success }) => { webLogger.debug(`notifyHostingDeploy: ${success}`); - setHostingState("deployed"); + setHostingState(success ? 'success' : 'failure'); }); }, []); @@ -156,18 +150,3 @@ export function SidebarApp() { ); } - -function InitFirebasePanel({ onHostingInit }: { onHostingInit: Function }) { - return ( - - Choose a path below to get started - - onHostingInit()}> - Host your web app - - - Free web hosting with a world-class CDN for peak performance - - - ); -} diff --git a/firebase-vscode/webviews/components/AccountSection.tsx b/firebase-vscode/webviews/components/AccountSection.tsx index 6b92a4a8d95..47bd62054ac 100644 --- a/firebase-vscode/webviews/components/AccountSection.tsx +++ b/firebase-vscode/webviews/components/AccountSection.tsx @@ -12,6 +12,7 @@ import { Label } from "./ui/Text"; import styles from "./AccountSection.scss"; import { ServiceAccountUser } from "../../common/types"; import { User } from "../../../src/types/auth"; +import { TEXT } from "../globals/ux-text"; export function AccountSection({ userEmail, @@ -25,24 +26,25 @@ export function AccountSection({ const [userDropdownVisible, toggleUserDropdown] = useState(false); const usersLoaded = !!allUsers; // Default: initial users check hasn't completed - let currentUserElement: ReactElement | string = "checking login"; + let currentUserElement: ReactElement | string = TEXT.LOGIN_PROGRESS; if (usersLoaded && !allUsers.length) { // Users loaded but no user was found if (isMonospace) { // Monospace: this is an error, should have found a workspace // service account - currentUserElement = "unable to find workspace service account"; + currentUserElement = TEXT.MONOSPACE_LOGIN_FAIL; } else { // VS Code: prompt user to log in with Google account - currentUserElement = ( broker.send("addUser")}> - Sign in with Google - ); + currentUserElement = ( + broker.send("addUser")}> + {TEXT.GOOGLE_SIGN_IN} + + ); } } else if (usersLoaded && allUsers.length > 0) { // Users loaded, at least one user was found - if (isMonospace && userEmail === 'service_account') { - // TODO(hsubox76): Figure out correct wording - currentUserElement = 'workspace logged in'; + if (isMonospace && userEmail === "service_account") { + currentUserElement = TEXT.MONOSPACE_LOGGED_IN; } else { currentUserElement = userEmail; } @@ -51,7 +53,7 @@ export function AccountSection({
    {!usersLoaded && (
    @@ -170,15 +187,17 @@ export function DeployPanel({ )} - {siteLink && ()} + {siteLink && ( + + )} diff --git a/firebase-vscode/webviews/components/InitPanel.tsx b/firebase-vscode/webviews/components/InitPanel.tsx new file mode 100644 index 00000000000..19de44d77b7 --- /dev/null +++ b/firebase-vscode/webviews/components/InitPanel.tsx @@ -0,0 +1,48 @@ +import { VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"; +import cn from "classnames"; + +import { Body, Label } from "./ui/Text"; +import React, { useState } from "react"; +import { TEXT } from "../globals/ux-text"; +import { PanelSection } from "./ui/PanelSection"; +import { Spacer } from "./ui/Spacer"; +import styles from "../sidebar.entry.scss"; + +export function InitFirebasePanel({ + onHostingInit, +}: { + onHostingInit: Function; +}) { + const [ initInProgress, setInitInProgress ] = useState(false); + if (initInProgress) { + return ( + + +
    + + +
    +
    + ); + } + return ( + + { + onHostingInit(); + setInitInProgress(true); + }} + > + {TEXT.INIT_HOSTING_BUTTON} + + + {TEXT.INIT_HOSTING_DESCRIPTION} + + + ); +} diff --git a/firebase-vscode/webviews/components/ProjectSection.tsx b/firebase-vscode/webviews/components/ProjectSection.tsx index 108b8d9641b..40ca46c3b29 100644 --- a/firebase-vscode/webviews/components/ProjectSection.tsx +++ b/firebase-vscode/webviews/components/ProjectSection.tsx @@ -6,6 +6,7 @@ import { Label } from "./ui/Text"; import React from "react"; import styles from "./AccountSection.scss"; import { ExternalLink } from "./ui/ExternalLink"; +import { TEXT } from "../globals/ux-text"; export function ProjectSection({ userEmail, @@ -60,7 +61,7 @@ export function ConnectProject({ userEmail }: { userEmail: string | null }) { return ( <> initProjectSelection(userEmail)}> - Connect a Firebase project + {TEXT.CONNECT_FIREBASE_PROJECT} ); @@ -72,7 +73,7 @@ export function ProjectInfo({ projectId }: { projectId: string }) { {projectId} ); diff --git a/firebase-vscode/webviews/components/ui/SplitButton.scss b/firebase-vscode/webviews/components/ui/SplitButton.scss new file mode 100644 index 00000000000..951be50ce25 --- /dev/null +++ b/firebase-vscode/webviews/components/ui/SplitButton.scss @@ -0,0 +1,38 @@ +.split-button { + display: flex; + position: relative; +} + +.main-target, +.menu-target { + &:focus { + z-index: 1; + } +} + +.main-target { + flex: 1 1 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.menu-target { + position: relative; + padding: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + --divider-vert-margin: 4px; + --button-padding-horizontal: 4px; + + &::before { + position: absolute; + left: 0; + top: var(--divider-vert-margin); + width: 1px; + height: calc(100% - var(--divider-vert-margin) * 2); + content: ''; + background-color: var(--vscode-button-foreground); + opacity: 0.2; + pointer-events: none; + } +} diff --git a/firebase-vscode/webviews/components/ui/SplitButton.tsx b/firebase-vscode/webviews/components/ui/SplitButton.tsx new file mode 100644 index 00000000000..a60144cd57e --- /dev/null +++ b/firebase-vscode/webviews/components/ui/SplitButton.tsx @@ -0,0 +1,53 @@ +import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"; +import cn from "classnames"; +import React, { HTMLAttributes, PropsWithChildren, useState } from "react"; +import { Icon } from "./Icon"; +import styles from "./SplitButton.scss"; +import { PopupMenu } from "./popup-menu/PopupMenu"; + +type SplitButtonProps = PropsWithChildren< + HTMLAttributes & { + appearance?: "primary" | "secondary"; + onClick: Function; + popupMenuContent: React.ReactNode; + } +>; + +export const SplitButton: React.FC = ({ + children, + onClick, + className, + popupMenuContent, + appearance, + ...props +}) => { + const [menuOpen, setMenuOpen] = useState(false); + + return ( + <> +
    + {menuOpen && ( + setMenuOpen(false)}> + {popupMenuContent} + + )} + + {children} + + setMenuOpen(true)} + appearance={appearance || "secondary"} + {...(props as any)} + > + + +
    + + ); +}; diff --git a/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx b/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx index a1a6e7b3aa4..a77ceee7213 100644 --- a/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx +++ b/firebase-vscode/webviews/components/ui/popup-menu/PopupMenu.tsx @@ -9,11 +9,13 @@ type PopupMenuProps = PropsWithChildren< HTMLAttributes & { show?: boolean; onClose: Function; + autoClose: boolean; } >; export const PopupMenu: FC> = ({ children, + autoClose, className, show, onClose, @@ -26,6 +28,9 @@ export const PopupMenu: FC> = ({
      { + autoClose && onClose(); + }} > {children}
    diff --git a/firebase-vscode/webviews/globals/ux-text.ts b/firebase-vscode/webviews/globals/ux-text.ts new file mode 100644 index 00000000000..d4d84521a1c --- /dev/null +++ b/firebase-vscode/webviews/globals/ux-text.ts @@ -0,0 +1,22 @@ +export const TEXT = { + INIT_HOSTING_BUTTON: "Host your Web App", + + INIT_HOSTING_DESCRIPTION: "Deploy your app with Firebase Hosting" + + ", a high-performance static web host backed by a global CDN", + + INIT_HOSTING_PROGRESS: "Initializing...", + + LOGIN_PROGRESS: "Checking login", + + MONOSPACE_LOGGED_IN: "Using default credentials", + + MONOSPACE_LOGIN_SELECTION_ITEM: "Default credentials", + + MONOSPACE_LOGIN_FAIL: "Unable to find default credentials", + + GOOGLE_SIGN_IN: "Sign in with Google", + + CONSOLE_LINK_DESCRIPTION: "Open in Firebase console", + + CONNECT_FIREBASE_PROJECT: "Connect a Firebase project" +}; diff --git a/firebase-vscode/webviews/tsconfig.json b/firebase-vscode/webviews/tsconfig.json index eb59f3c1eac..e689c6113ab 100644 --- a/firebase-vscode/webviews/tsconfig.json +++ b/firebase-vscode/webviews/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "module": "None", + "module": "es2020", "moduleResolution": "Node", "target": "ES2020", "lib": ["ES2020", "DOM"], diff --git a/firebase-vscode/webviews/webview-types.ts b/firebase-vscode/webviews/webview-types.ts index ebe64febd7a..372d6ffbee6 100644 --- a/firebase-vscode/webviews/webview-types.ts +++ b/firebase-vscode/webviews/webview-types.ts @@ -1,2 +1,2 @@ -export type HostingState = null | "deployed" | "deploying"; +export type HostingState = null | "success" | "failure" | "deploying"; diff --git a/src/config.ts b/src/config.ts index 85ed4fa4d92..9da92c32d28 100644 --- a/src/config.ts +++ b/src/config.ts @@ -273,6 +273,7 @@ export class Config { throw new FirebaseError("Not in a Firebase app directory (could not locate firebase.json)", { exit: 1, + status: 404, }); } } diff --git a/src/deploy/hosting/prepare.ts b/src/deploy/hosting/prepare.ts index df55b527330..dabb448243e 100644 --- a/src/deploy/hosting/prepare.ts +++ b/src/deploy/hosting/prepare.ts @@ -12,6 +12,7 @@ import * as utils from "../../utils"; import { HostingSource, RunRewrite } from "../../firebaseConfig"; import * as backend from "../functions/backend"; import { ensureTargeted } from "../../functions/ensureTargeted"; +import { normalizeAndValidate } from "../../functions/projectConfig"; function handlePublicDirectoryFlag(options: HostingOptions & Options): void { // Allow the public directory to be overridden by the --public flag @@ -75,8 +76,20 @@ export async function addPinnedFunctionsToOnlyString( if (endpoint) { options.only = ensureTargeted(options.only, endpoint.codebase || "default", endpoint.id); } else { - // This endpoint is just being added in this push. We don't know what codebase it is. - options.only = ensureTargeted(options.only, r.function.functionId); + const functionsConfig = normalizeAndValidate(options.config.src.functions); + const codebasesFromConfig = [ + ...new Set(Object.values(functionsConfig).map((c) => c.codebase)), + ]; + if (codebasesFromConfig.length > 0) { + options.only = ensureTargeted( + options.only, + codebasesFromConfig[0], + r.function.functionId + ); + } else { + // This endpoint is just being added in this push. We don't know what codebase it is. + options.only = ensureTargeted(options.only, r.function.functionId); + } } addedFunctionsPerSite.push(r.function.functionId); } diff --git a/src/detectProjectRoot.ts b/src/detectProjectRoot.ts index de39911690a..a336b38d468 100644 --- a/src/detectProjectRoot.ts +++ b/src/detectProjectRoot.ts @@ -7,7 +7,10 @@ export function detectProjectRoot(options: { cwd?: string; configPath?: string } if (options.configPath) { const fullPath = resolve(projectRootDir, options.configPath); if (!fileExistsSync(fullPath)) { - throw new FirebaseError(`Could not load config file ${options.configPath}.`, { exit: 1 }); + throw new FirebaseError(`Could not load config file ${options.configPath}.`, { + exit: 1, + status: 404, + }); } return dirname(fullPath); diff --git a/src/functionsConfig.ts b/src/functionsConfig.ts index 7d984e8574e..169570640c8 100644 --- a/src/functionsConfig.ts +++ b/src/functionsConfig.ts @@ -113,7 +113,7 @@ export async function setVariablesRecursive( export async function materializeConfig(configName: string, output: any): Promise { const materializeVariable = async function (varName: string) { const variable = await runtimeconfig.variables.get(varName); - const id = exports.varNameToIds(variable.name); + const id = varNameToIds(variable.name); const key = id.config + "." + id.variable.split("/").join("."); _.set(output, key, variable.text); }; @@ -143,7 +143,7 @@ export async function materializeAll(projectId: string): Promise Date: Wed, 21 Jun 2023 15:24:09 -0700 Subject: [PATCH 071/320] Missed a few changes from comments (#6015) * Fixed a bug in the hosting config for emulators. Also fixed an issue where an empty folder creates an issue loading the side panel. * Missed some changes * Update firebase-vscode/webviews/components/EmulatorPanel.tsx Co-authored-by: joehan --------- Co-authored-by: joehan --- firebase-vscode/webviews/SidebarApp.tsx | 2 +- .../{ => components}/EmulatorPanel.tsx | 45 +++++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) rename firebase-vscode/webviews/{ => components}/EmulatorPanel.tsx (87%) diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx index 86a9ef0a3f6..c5f9e9bd77d 100644 --- a/firebase-vscode/webviews/SidebarApp.tsx +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -9,7 +9,7 @@ import { ServiceAccountUser } from "../common/types"; import { DeployPanel } from "./components/DeployPanel"; import { HostingState } from "./webview-types"; import { ChannelWithId } from "./messaging/types"; -import { EmulatorPanel } from "./EmulatorPanel"; +import { EmulatorPanel } from "./components/EmulatorPanel"; import { webLogger } from "./globals/web-logger"; import { InitFirebasePanel } from "./components/InitPanel"; diff --git a/firebase-vscode/webviews/EmulatorPanel.tsx b/firebase-vscode/webviews/components/EmulatorPanel.tsx similarity index 87% rename from firebase-vscode/webviews/EmulatorPanel.tsx rename to firebase-vscode/webviews/components/EmulatorPanel.tsx index 3d35146a1a7..a894376b989 100644 --- a/firebase-vscode/webviews/EmulatorPanel.tsx +++ b/firebase-vscode/webviews/components/EmulatorPanel.tsx @@ -7,18 +7,18 @@ import { VSCodeTextField, } from "@vscode/webview-ui-toolkit/react"; import React, { useState } from "react"; -import { Spacer } from "./components/ui/Spacer"; -import { broker } from "./globals/html-broker"; -import { PanelSection } from "./components/ui/PanelSection"; -import { FirebaseConfig } from "../../src/firebaseConfig"; +import { Spacer } from "./ui/Spacer"; +import { broker } from "../globals/html-broker"; +import { PanelSection } from "./ui/PanelSection"; +import { FirebaseConfig } from "../../../src/firebaseConfig"; import { RunningEmulatorInfo, EmulatorUiSelections, -} from "../common/messaging/types"; +} from "../../common/messaging/types"; import { VSCodeDropdown } from "@vscode/webview-ui-toolkit/react"; import { VSCodeOption } from "@vscode/webview-ui-toolkit/react"; -import { EmulatorInfo } from "../../src/emulator/types"; -import { webLogger } from "./globals/web-logger"; +import { EmulatorInfo } from "../../../src/emulator/types"; +import { webLogger } from "../globals/web-logger"; const DEFAULT_EMULATOR_UI_SELECTIONS: EmulatorUiSelections = { projectId: "demo-something", @@ -41,7 +41,7 @@ export function EmulatorPanel({ if (!firebaseJson) { throw Error("Expected a valid FirebaseConfig."); } - var defaultState = DEFAULT_EMULATOR_UI_SELECTIONS; + const defaultState = DEFAULT_EMULATOR_UI_SELECTIONS; if (projectId) { defaultState.projectId = getProjectIdForMode(projectId, defaultState.mode); } @@ -83,8 +83,11 @@ export function EmulatorPanel({ webLogger.debug( `notifyEmulatorImportFolder received in sidebar: ${folder}` ); - emulatorUiSelections.importStateFolderPath = folder; - setEmulatorUiSelectionsAndSaveToWorkspace({ ...emulatorUiSelections }); // rerender clone + const newSelections = { + ...emulatorUiSelections, + importStateFolderPath: folder, + }; + setEmulatorUiSelectionsAndSaveToWorkspace(newSelections); }); function launchEmulators() { @@ -145,16 +148,22 @@ export function EmulatorPanel({ function emulatorModeChanged(event: React.ChangeEvent) { webLogger.debug("emulatorModeChanged: " + event.target.value); - const selections: EmulatorUiSelections = emulatorUiSelections; - selections.mode = event.target.value as typeof emulatorUiSelections.mode; - selections.projectId = getProjectIdForMode(projectId, selections.mode); - setEmulatorUiSelectionsAndSaveToWorkspace({...selections}); + const newSelections: EmulatorUiSelections = { ...emulatorUiSelections }; + newSelections.mode = event.target.value as typeof emulatorUiSelections.mode; + newSelections.projectId = getProjectIdForMode( + projectId, + newSelections.mode + ); + setEmulatorUiSelectionsAndSaveToWorkspace(newSelections); } function clearImportFolder() { console.log(`clearImportFolder`); - emulatorUiSelections.importStateFolderPath = ""; - setEmulatorUiSelectionsAndSaveToWorkspace({ ...emulatorUiSelections }); + const newSelections = { + ...emulatorUiSelections, + importStateFolderPath: "", + }; + setEmulatorUiSelectionsAndSaveToWorkspace(newSelections); } // Make it pretty for the screen. Filter out the logging emulator since it's @@ -261,7 +270,7 @@ export function EmulatorPanel({ /** * Formats a project ID with a demo prefix if we're in offline mode, or uses the - * regular ID if we're hosting. + * regular ID if we're in hosting only mode. */ function getProjectIdForMode( projectId: string | undefined, @@ -274,4 +283,4 @@ function getProjectIdForMode( return projectId; } return "demo-" + projectId; -} \ No newline at end of file +} From 05c3013131f42e9d61952a9da9e20da5a8a0e20f Mon Sep 17 00:00:00 2001 From: Chalo Salvador Date: Thu, 22 Jun 2023 15:29:49 +0200 Subject: [PATCH 072/320] Fix firebase emulators:start crashing (#6005) * Update proxyResponse method * Add proper types to proxyResponse function * Changelog * Changelog formatting * Update CHANGELOG.md * Update firebase-vscode/package-lock.json --------- Co-authored-by: joehan --- CHANGELOG.md | 1 + firebase-vscode/package-lock.json | 4 +- src/frameworks/utils.ts | 110 +++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d9ab78675..c93ac2e5b19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ - Run lifecycle hooks for specific codebases. (#6011) +- Fixed issue causing `firebase emulators:start` to crash in Next.js apps (#6005) diff --git a/firebase-vscode/package-lock.json b/firebase-vscode/package-lock.json index a9525311ad3..56f8dbfade9 100644 --- a/firebase-vscode/package-lock.json +++ b/firebase-vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "firebase-vscode", - "version": "0.0.22", + "version": "0.0.22-alpha.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-vscode", - "version": "0.0.22", + "version": "0.0.22-alpha.0", "dependencies": { "@vscode/codicons": "0.0.30", "@vscode/webview-ui-toolkit": "^1.2.1", diff --git a/src/frameworks/utils.ts b/src/frameworks/utils.ts index 6967534c740..299232a9572 100644 --- a/src/frameworks/utils.ts +++ b/src/frameworks/utils.ts @@ -63,20 +63,97 @@ export async function warnIfCustomBuildScript( } } -function proxyResponse(original: ServerResponse, next: () => void) { - return (response: IncomingMessage | ServerResponse) => { - const { statusCode, statusMessage } = response; - if (!statusCode) { - original.end(); - return; - } - if (statusCode === 404) { - return next(); - } - const headers = "getHeaders" in response ? response.getHeaders() : response.headers; - original.writeHead(statusCode, statusMessage, headers); - response.pipe(original); - }; +/** + * Proxy a HTTP response + * It uses the Proxy object to intercept the response and buffer it until the + * response is finished. This allows us to modify the response before sending + * it back to the client. + */ +export function proxyResponse( + req: IncomingMessage, + res: ServerResponse, + next: () => void +): ServerResponse { + const proxiedRes = new ServerResponse(req); + // Object to store the original response methods + const buffer: [ + string, + Parameters + ][] = []; + + // Proxy the response methods + // The apply handler is called when the method e.g. write, setHeader, etc. is called + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply + // The target is the original method + // The thisArg is the proxied response + // The args are the arguments passed to the method + proxiedRes.write = new Proxy(proxiedRes.write.bind(proxiedRes), { + apply: ( + target: ServerResponse["write"], + thisArg: ServerResponse, + args: Parameters + ) => { + // call the original write method on the proxied response + target.call(thisArg, ...args); + // store the method call in the buffer + buffer.push(["write", args]); + }, + }); + + proxiedRes.setHeader = new Proxy(proxiedRes.setHeader.bind(proxiedRes), { + apply: ( + target: ServerResponse["setHeader"], + thisArg: ServerResponse, + args: Parameters + ) => { + target.call(thisArg, ...args); + buffer.push(["setHeader", args]); + }, + }); + proxiedRes.removeHeader = new Proxy(proxiedRes.removeHeader.bind(proxiedRes), { + apply: ( + target: ServerResponse["removeHeader"], + thisArg: ServerResponse, + args: Parameters + ) => { + target.call(thisArg, ...args); + buffer.push(["removeHeader", args]); + }, + }); + proxiedRes.writeHead = new Proxy(proxiedRes.writeHead.bind(proxiedRes), { + apply: ( + target: ServerResponse["writeHead"], + thisArg: ServerResponse, + args: Parameters + ) => { + target.call(thisArg, ...args); + buffer.push(["writeHead", args]); + }, + }); + proxiedRes.end = new Proxy(proxiedRes.end.bind(proxiedRes), { + apply: ( + target: ServerResponse["end"], + thisArg: ServerResponse, + args: Parameters + ) => { + // call the original end method on the proxied response + target.call(thisArg, ...args); + // if the proxied response is a 404, call next to continue down the middleware chain + // otherwise, send the buffered response i.e. call the original response methods: write, setHeader, etc. + // and then end the response and clear the buffer + if (proxiedRes.statusCode === 404) { + next(); + } else { + for (const [fn, args] of buffer) { + (res as any)[fn](...args); + } + res.end(...args); + buffer.length = 0; + } + }, + }); + + return proxiedRes; } export function simpleProxy(hostOrRequestHandler: string | RequestHandler) { @@ -127,9 +204,8 @@ export function simpleProxy(hostOrRequestHandler: string | RequestHandler) { originalRes.end(); }); } else { - await Promise.resolve(hostOrRequestHandler(originalReq, originalRes, next)); - const proxiedRes = new ServerResponse(originalReq); - proxyResponse(originalRes, next)(proxiedRes); + const proxiedRes = proxyResponse(originalReq, originalRes, next); + await hostOrRequestHandler(originalReq, proxiedRes, next); } }; } From 85303344a394ce4910d9d67a11b39e0d5fb76e7e Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 22 Jun 2023 11:38:36 -0700 Subject: [PATCH 073/320] Revert incorrectly included code (#6022) --- src/deploy/hosting/prepare.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/deploy/hosting/prepare.ts b/src/deploy/hosting/prepare.ts index dabb448243e..df55b527330 100644 --- a/src/deploy/hosting/prepare.ts +++ b/src/deploy/hosting/prepare.ts @@ -12,7 +12,6 @@ import * as utils from "../../utils"; import { HostingSource, RunRewrite } from "../../firebaseConfig"; import * as backend from "../functions/backend"; import { ensureTargeted } from "../../functions/ensureTargeted"; -import { normalizeAndValidate } from "../../functions/projectConfig"; function handlePublicDirectoryFlag(options: HostingOptions & Options): void { // Allow the public directory to be overridden by the --public flag @@ -76,20 +75,8 @@ export async function addPinnedFunctionsToOnlyString( if (endpoint) { options.only = ensureTargeted(options.only, endpoint.codebase || "default", endpoint.id); } else { - const functionsConfig = normalizeAndValidate(options.config.src.functions); - const codebasesFromConfig = [ - ...new Set(Object.values(functionsConfig).map((c) => c.codebase)), - ]; - if (codebasesFromConfig.length > 0) { - options.only = ensureTargeted( - options.only, - codebasesFromConfig[0], - r.function.functionId - ); - } else { - // This endpoint is just being added in this push. We don't know what codebase it is. - options.only = ensureTargeted(options.only, r.function.functionId); - } + // This endpoint is just being added in this push. We don't know what codebase it is. + options.only = ensureTargeted(options.only, r.function.functionId); } addedFunctionsPerSite.push(r.function.functionId); } From 87968f0d3b5a71ee7e6b89d4efa2dd633a2510f4 Mon Sep 17 00:00:00 2001 From: Sairam Sakhamuri Date: Thu, 22 Jun 2023 12:28:46 -0700 Subject: [PATCH 074/320] Init flow frameworks cli. (#6010) * Added init flow commands * change region name * Enable frameworkstacks api * Added code review changes * Revert unwanted changes * Revert unwanted changes * Revert unwanted changes * change according to project id * Removed unwanted statements related to projectId --- src/commands/init.ts | 10 ++++ src/experiments.ts | 6 +++ src/init/features/frameworks/constants.ts | 4 ++ src/init/features/frameworks/index.ts | 57 +++++++++++++++++++++++ src/init/features/index.ts | 1 + src/init/index.ts | 5 ++ 6 files changed, 83 insertions(+) create mode 100644 src/init/features/frameworks/constants.ts create mode 100644 src/init/features/frameworks/index.ts diff --git a/src/commands/init.ts b/src/commands/init.ts index 9a306947dc4..4987bc82e65 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -13,6 +13,7 @@ import { requireAuth } from "../requireAuth"; import * as fsutils from "../fsutils"; import * as utils from "../utils"; import { Options } from "../options"; +import { isEnabled } from "../experiments"; const homeDir = os.homedir(); @@ -71,6 +72,15 @@ const choices = [ checked: false, }, ]; + +if (isEnabled("frameworks")) { + choices.push({ + value: "frameworks", + name: "Frameworks: Get started with Frameworks projects.", + checked: false, + }); +} + const featureNames = choices.map((choice) => choice.value); const DESCRIPTION = `Interactively configure the current directory as a Firebase project or initialize new features in an already configured Firebase project directory. diff --git a/src/experiments.ts b/src/experiments.ts index 8ad9ff4e2b9..0d61ba57082 100644 --- a/src/experiments.ts +++ b/src/experiments.ts @@ -97,6 +97,12 @@ export const ALL_EXPERIMENTS = experiments({ "These commands are not meant for public consumption and may break or disappear " + "without a notice.", }, + + frameworks: { + shortDescription: "Allow CLI option for Frameworks", + default: true, + public: false, + }, }); export type ExperimentName = keyof typeof ALL_EXPERIMENTS; diff --git a/src/init/features/frameworks/constants.ts b/src/init/features/frameworks/constants.ts new file mode 100644 index 00000000000..90731f7858e --- /dev/null +++ b/src/init/features/frameworks/constants.ts @@ -0,0 +1,4 @@ +export const DEFAULT_REGION = "us-central1"; +export const ALLOWED_REGIONS = [{ name: "us-central1 (Iowa)", value: "us-central1" }]; +export const DEFAULT_DEPLOY_METHOD = "github"; +export const ALLOWED_DEPLOY_METHODS = [{ name: "Deploy using github", value: "github" }]; diff --git a/src/init/features/frameworks/index.ts b/src/init/features/frameworks/index.ts new file mode 100644 index 00000000000..8b75e5023c9 --- /dev/null +++ b/src/init/features/frameworks/index.ts @@ -0,0 +1,57 @@ +import * as clc from "colorette"; +import * as utils from "../../../utils"; +import { logger } from "../../../logger"; +import { promptOnce } from "../../../prompt"; +import { + DEFAULT_REGION, + ALLOWED_REGIONS, + DEFAULT_DEPLOY_METHOD, + ALLOWED_DEPLOY_METHODS, +} from "./constants"; + +/** + * Setup new frameworks project. + */ +export async function doSetup(setup: any): Promise { + setup.frameworks = {}; + + utils.logBullet("First we need a few details to create your service."); + + await promptOnce( + { + name: "serviceName", + type: "input", + default: "acme-inc-web", + message: "Create a name for your service [6-32 characters]", + }, + setup.frameworks + ); + + await promptOnce( + { + name: "region", + type: "list", + default: DEFAULT_REGION, + message: + "Please select a region " + + `(${clc.yellow("info")}: Your region determines where your backend is located):\n`, + choices: ALLOWED_REGIONS, + }, + setup.frameworks + ); + + utils.logSuccess(`Region set to ${setup.frameworks.region}.`); + + logger.info(clc.bold(`\n${clc.white("===")} Deploy Setup`)); + + await promptOnce( + { + name: "deployMethod", + type: "list", + default: DEFAULT_DEPLOY_METHOD, + message: "How do you want to deploy", + choices: ALLOWED_DEPLOY_METHODS, + }, + setup.frameworks + ); +} diff --git a/src/init/features/index.ts b/src/init/features/index.ts index a52bfd6f400..afbfa51f652 100644 --- a/src/init/features/index.ts +++ b/src/init/features/index.ts @@ -10,3 +10,4 @@ export { doSetup as extensions } from "./extensions"; export { doSetup as project } from "./project"; export { doSetup as remoteconfig } from "./remoteconfig"; export { initGitHub as hostingGithub } from "./hosting/github"; +export { doSetup as frameworks } from "./frameworks"; diff --git a/src/init/index.ts b/src/init/index.ts index 19565c19769..e3b7557b4df 100644 --- a/src/init/index.ts +++ b/src/init/index.ts @@ -4,6 +4,7 @@ import * as clc from "colorette"; import { FirebaseError } from "../error"; import { logger } from "../logger"; import * as features from "./features"; +import { isEnabled } from "../experiments"; export interface Setup { config: Record; @@ -31,6 +32,10 @@ const featureFns = new Map P ["hosting:github", features.hostingGithub], ]); +if (isEnabled("frameworks")) { + featureFns.set("frameworks", features.frameworks); +} + export async function init(setup: Setup, config: any, options: any): Promise { const nextFeature = setup.features?.shift(); if (nextFeature) { From 9330b35726a55eb997115ace86ff8a9192727422 Mon Sep 17 00:00:00 2001 From: Sairam Sakhamuri Date: Thu, 22 Jun 2023 12:52:43 -0700 Subject: [PATCH 075/320] Frameworks (#6012) * Initial commit to stacks api * Added more properties to the Stack and Build object * Added api calls for framework stacks * Changed naming * Changed naming * Review changes * Removed and used minimal fields * Moved frameworks api file --- src/api.ts | 4 ++ src/api/frameworks.ts | 117 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/api/frameworks.ts diff --git a/src/api.ts b/src/api.ts index c20ead3091b..0a362e63758 100644 --- a/src/api.ts +++ b/src/api.ts @@ -173,6 +173,10 @@ export const serviceUsageOrigin = utils.envOverride( "FIREBASE_SERVICE_USAGE_URL", "https://serviceusage.googleapis.com" ); +export const frameworksOrigin = utils.envOverride( + "FRAMEWORKS_URL", + "https://placeholder.googleapis.com" +); export const githubOrigin = utils.envOverride("GITHUB_URL", "https://github.com"); export const githubApiOrigin = utils.envOverride("GITHUB_API_URL", "https://api.github.com"); export const secretManagerOrigin = utils.envOverride( diff --git a/src/api/frameworks.ts b/src/api/frameworks.ts new file mode 100644 index 00000000000..30fcc41bd66 --- /dev/null +++ b/src/api/frameworks.ts @@ -0,0 +1,117 @@ +import { Client } from "../apiv2"; +import { frameworksOrigin } from "../api"; + +export const API_VERSION = "v1"; + +const client = new Client({ + urlPrefix: frameworksOrigin, + auth: true, + apiVersion: API_VERSION, +}); + +export type State = "BUILDING" | "BUILD" | "DEPLOYING" | "READY" | "FAILED"; + +interface Codebase { + repository?: string; + rootDirectory: string; +} + +/** A Stack, the primary resource of Frameworks. */ +interface Stack { + name: string; + mode?: string; + codebase: Codebase; + labels: Record; + createTime: string; + updateTime: string; + uri: string; +} + +export type StackOutputOnlyFields = "createTime" | "updateTime" | "uri"; + +interface Build { + name: string; + state: State; + error: Status; + image: string; + source: BuildSource; + buildLogsUri: string; + createTime: Date; + updateTime: Date; + sourceRef: string; +} + +export type BuildOutputOnlyFields = "createTime" | "updateTime" | "sourceRef"; + +interface BuildSource { + codeBaseSource?: CodebaseSource; +} + +interface Status { + code: number; + message: string; + details: any[]; +} + +interface CodebaseSource { + // oneof reference + branch: string; + commit: string; + tag: string; + // end oneof reference +} + +export interface OperationMetadata { + createTime: string; + endTime: string; + target: string; + verb: string; + statusDetail: string; + cancelRequested: boolean; + apiVersion: string; +} + +export interface Operation { + name: string; + metadata?: OperationMetadata; + done: boolean; + // oneof result + error?: Status; + response?: any; + // end oneof result +} + +/** + * Creates a new Stack in a given project and location. + */ +export async function createStack( + projectId: string, + location: string, + stackId: string, + stack: Stack +): Promise { + const res = await client.post, Operation>( + `projects/${projectId}/locations/${location}/stacks`, + stack, + { queryParams: { stackId } } + ); + return res.body; +} + +/** + * Creates a new Build in a given project and location. + */ +export async function createBuild( + projectId: string, + location: string, + stackId: string, + buildId: string, + build: Build +): Promise { + const res = await client.post, Operation>( + `projects/${projectId}/locations/${location}/stacks/${stackId}/builds`, + build, + { queryParams: { buildId } } + ); + return res.body; +} From 728d07da7304c382b4e34be2c634b269b2fd1558 Mon Sep 17 00:00:00 2001 From: joehan Date: Thu, 22 Jun 2023 16:13:21 -0700 Subject: [PATCH 076/320] Switched most uses of track to GA4 (#6016) * Switched most uses of track to GA4 * Move duration out of params, and improve debug logging slightly --- src/auth.ts | 8 +- src/command.ts | 25 ++- src/commands/ext-install.ts | 13 +- src/deploy/functions/checkIam.ts | 7 +- src/deploy/hosting/prepare.ts | 6 +- src/deploy/index.ts | 21 ++- src/emulator/controller.ts | 4 +- src/emulator/functionsEmulator.ts | 4 +- src/ensureApiEnabled.ts | 6 +- src/extensions/paramHelper.ts | 5 - src/test/deploy/hosting/prepare.spec.ts | 8 +- src/track.ts | 206 ++++++++++++++++-------- 12 files changed, 207 insertions(+), 106 deletions(-) diff --git a/src/auth.ts b/src/auth.ts index 56e5f31cdd9..4ab586b3c0e 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -19,7 +19,7 @@ import * as scopes from "./scopes"; import { clearCredentials } from "./defaultCredentials"; import { v4 as uuidv4 } from "uuid"; import { randomBytes, createHash } from "crypto"; -import { track } from "./track"; +import { trackGA4 } from "./track"; import { authOrigin, authProxyOrigin, @@ -444,7 +444,7 @@ async function loginRemotely(): Promise { codeVerifier ); - void track("login", "google_remote"); + void trackGA4("login", { method: "google_remote" }); return { user: jwt.decode(tokens.id_token!) as User, @@ -468,7 +468,7 @@ async function loginWithLocalhostGoogle(port: number, userHint?: string): Promis getTokensFromAuthorizationCode ); - void track("login", "google_localhost"); + void trackGA4("login", { method: "google_localhost" }); // getTokensFromAuthoirzationCode doesn't handle the --token case, so we know we'll // always have an id_token. return { @@ -489,7 +489,7 @@ async function loginWithLocalhostGitHub(port: number): Promise { successTemplate, getGithubTokensFromAuthorizationCode ); - void track("login", "google_localhost"); + void trackGA4("login", { method: "github_localhost" }); return tokens; } diff --git a/src/command.ts b/src/command.ts index 86edffbc791..1d14255071e 100644 --- a/src/command.ts +++ b/src/command.ts @@ -8,7 +8,7 @@ import { loadRC } from "./rc"; import { Config } from "./config"; import { configstore } from "./configstore"; import { detectProjectRoot } from "./detectProjectRoot"; -import { track, trackEmulator } from "./track"; +import { trackEmulator, trackGA4 } from "./track"; import { selectAccount, setActiveAccount } from "./auth"; import { getFirebaseProject } from "./management/projects"; import { requireAuth } from "./requireAuth"; @@ -202,7 +202,12 @@ export class Command { ); } const duration = Math.floor((process.uptime() - start) * 1000); - const trackSuccess = track(this.name, "success", duration); + const trackSuccess = trackGA4("command_execution", { + command_name: this.name, + result: "success", + duration, + interactive: getInheritedOption(options, "nonInteractive") ? "false" : "true", + }); if (!isEmulator) { await withTimeout(5000, trackSuccess); } else { @@ -236,8 +241,15 @@ export class Command { await withTimeout( 5000, Promise.all([ - track(this.name, "error", duration), - track(err.exit === 1 ? "Error (User)" : "Error (Unexpected)", "", duration), + trackGA4( + "command_execution", + { + command_name: this.name, + result: "error", + interactive: getInheritedOption(options, "nonInteractive") ? "false" : "true", + }, + duration + ), isEmulator ? trackEmulator("command_error", { command_name: this.name, @@ -400,7 +412,10 @@ export function validateProjectId(project: string): void { if (PROJECT_ID_REGEX.test(project)) { return; } - track("Project ID Check", "invalid"); + trackGA4("error", { + error_type: "Error (User)", + details: "Invalid project ID", + }); const invalidMessage = "Invalid project id: " + clc.bold(project) + "."; if (project.toLowerCase() !== project) { // Attempt to be more helpful in case uppercase letters are used. diff --git a/src/commands/ext-install.ts b/src/commands/ext-install.ts index d4fe999a397..35e55d2d09c 100644 --- a/src/commands/ext-install.ts +++ b/src/commands/ext-install.ts @@ -27,7 +27,7 @@ import { import { getRandomString } from "../extensions/utils"; import { requirePermissions } from "../requirePermissions"; import * as utils from "../utils"; -import { track } from "../track"; +import { trackGA4 } from "../track"; import { confirm } from "../prompt"; import { Options } from "../options"; import * as manifest from "../extensions/manifest"; @@ -96,11 +96,18 @@ export const command = new Command("ext:install [extensionName]") // Should parse spec locally so we don't need project ID. source = await createSourceFromLocation(needProjectId({ projectId }), extensionName); await displayExtInfo(extensionName, "", source.spec); - void track("Extension Install", "Install by Source", options.interactive ? 1 : 0); + void trackGA4("extension_added_to_manifest", { + published: "local", + interactive: options.nonInteractive ? "false" : "true", + }); } else { - void track("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0); extensionName = await canonicalizeRefInput(extensionName); extensionVersion = await extensionsApi.getExtensionVersion(extensionName); + + void trackGA4("extension_added_to_manifest", { + published: extensionVersion.listing?.state === "APPROVED" ? "published" : "uploaded", + interactive: options.nonInteractive ? "false" : "true", + }); await infoExtensionVersion({ extensionName, extensionVersion, diff --git a/src/deploy/functions/checkIam.ts b/src/deploy/functions/checkIam.ts index 8b4a0d1d692..20f61599ad2 100644 --- a/src/deploy/functions/checkIam.ts +++ b/src/deploy/functions/checkIam.ts @@ -8,7 +8,7 @@ import { flattenArray } from "../../functional"; import * as iam from "../../gcp/iam"; import * as args from "./args"; import * as backend from "./backend"; -import { track } from "../../track"; +import { trackGA4 } from "../../track"; import * as utils from "../../utils"; import { getIamPolicy, setIamPolicy } from "../../gcp/resourceManager"; @@ -101,7 +101,10 @@ export async function checkHttpIam( } if (!passed) { - void track("Error (User)", "deploy:functions:http_create_missing_iam"); + void trackGA4("error", { + error_type: "Error (User)", + details: "deploy:functions:http_create_missing_iam", + }); throw new FirebaseError( `Missing required permission on project ${bold( context.projectId diff --git a/src/deploy/hosting/prepare.ts b/src/deploy/hosting/prepare.ts index df55b527330..0a6223c39bf 100644 --- a/src/deploy/hosting/prepare.ts +++ b/src/deploy/hosting/prepare.ts @@ -7,7 +7,7 @@ import { Context } from "./context"; import { Options } from "../../options"; import { HostingOptions } from "../../hosting/options"; import { assertExhaustive, zipIn } from "../../functional"; -import { track } from "../../track"; +import { trackGA4 } from "../../track"; import * as utils from "../../utils"; import { HostingSource, RunRewrite } from "../../firebaseConfig"; import * as backend from "../functions/backend"; @@ -137,7 +137,9 @@ export async function prepare(context: Context, options: HostingOptions & Option labels, }; const [, versionName] = await Promise.all([ - track("hosting_deploy", config.webFramework || "classic"), + trackGA4("hosting_version", { + framework: config.webFramework || "classic", + }), api.createVersion(config.site, version), ]); return versionName; diff --git a/src/deploy/index.ts b/src/deploy/index.ts index 54a64b571cb..99d2bb5eccb 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -2,11 +2,11 @@ import * as clc from "colorette"; import { logger } from "../logger"; import { hostingOrigin } from "../api"; import { bold, underline, white } from "colorette"; -import { has, includes, each } from "lodash"; +import { includes, each } from "lodash"; import { needProjectId } from "../projectUtils"; import { logBullet, logSuccess, consoleUrl, addSubdomain } from "../utils"; import { FirebaseError } from "../error"; -import { track } from "../track"; +import { AnalyticsParams, trackGA4 } from "../track"; import { lifecycleHooks } from "./lifecycleHooks"; import * as experiments from "../experiments"; import * as HostingTarget from "./hosting"; @@ -119,12 +119,19 @@ export const deploy = async function ( await chain(releases, context, options, payload); await chain(postdeploys, context, options, payload); - if (has(options, "config.notes.databaseRules")) { - await track("Rules Deploy", options.config.notes.databaseRules); - } - const duration = Date.now() - startTime; - await track("Product Deploy", [...targetNames].sort().join(","), duration); + const analyticsParams: AnalyticsParams = { + interactive: options.nonInteractive ? "false" : "true", + }; + + Object.keys(TARGETS).reduce((accum, t) => { + accum[t] = "false"; + return accum; + }, analyticsParams); + for (const t of targetNames) { + analyticsParams[t] = "true"; + } + await trackGA4("product_deploy", analyticsParams, duration); logger.info(); logSuccess(bold(underline("Deploy complete!"))); diff --git a/src/emulator/controller.ts b/src/emulator/controller.ts index a837d5d2d7d..7505bf9ea81 100644 --- a/src/emulator/controller.ts +++ b/src/emulator/controller.ts @@ -4,7 +4,7 @@ import * as path from "path"; import * as fsConfig from "../firestore/fsConfig"; import { logger } from "../logger"; -import { track, trackEmulator } from "../track"; +import { trackEmulator } from "../track"; import * as utils from "../utils"; import { EmulatorRegistry } from "./registry"; import { @@ -401,7 +401,6 @@ export async function startAll( const name = instance.getName(); // Log the command for analytics - void track("Emulator Run", name); void trackEmulator("emulator_run", { emulator_name: name, is_demo_project: String(isDemoProject), @@ -421,7 +420,6 @@ export async function startAll( // since we originally mistakenly reported emulators:start events // for each emulator, by reporting the "hub" we ensure that our // historical data can still be viewed. - void track("emulators:start", "hub"); await startEmulator(hub); } diff --git a/src/emulator/functionsEmulator.ts b/src/emulator/functionsEmulator.ts index f350d2d6d33..a3f93206585 100644 --- a/src/emulator/functionsEmulator.ts +++ b/src/emulator/functionsEmulator.ts @@ -11,7 +11,7 @@ import { EventEmitter } from "events"; import { Account } from "../types/auth"; import { logger } from "../logger"; -import { track, trackEmulator } from "../track"; +import { trackEmulator } from "../track"; import { Constants } from "./constants"; import { EmulatorInfo, EmulatorInstance, Emulators, FunctionsExecutionMode } from "./types"; import * as chokidar from "chokidar"; @@ -63,7 +63,6 @@ import { resolveBackend } from "../deploy/functions/build"; import { setEnvVarsForEmulators } from "./env"; import { runWithVirtualEnv } from "../functions/python"; -const EVENT_INVOKE = "functions:invoke"; // event name for UA const EVENT_INVOKE_GA4 = "functions_invoke"; // event name GA4 (alphanumertic) /* @@ -1551,7 +1550,6 @@ export class FunctionsEmulator implements EmulatorInstance { } } // For analytics, track the invoked service - void track(EVENT_INVOKE, getFunctionService(trigger)); void trackEmulator(EVENT_INVOKE_GA4, { function_service: getFunctionService(trigger), }); diff --git a/src/ensureApiEnabled.ts b/src/ensureApiEnabled.ts index 48d0044f046..d0da2ba8b21 100644 --- a/src/ensureApiEnabled.ts +++ b/src/ensureApiEnabled.ts @@ -1,6 +1,6 @@ import { bold } from "colorette"; -import { track } from "./track"; +import { trackGA4 } from "./track"; import { serviceUsageOrigin } from "./api"; import { Client } from "./apiv2"; import * as utils from "./utils"; @@ -91,7 +91,9 @@ async function pollCheckEnabled( }); const isEnabled = await check(projectId, apiName, prefix, silent); if (isEnabled) { - void track("api_enabled", apiName); + void trackGA4("api_enabled", { + api_name: apiName, + }); return; } if (!silent) { diff --git a/src/extensions/paramHelper.ts b/src/extensions/paramHelper.ts index 8231d69ebaf..aca46a91d4d 100644 --- a/src/extensions/paramHelper.ts +++ b/src/extensions/paramHelper.ts @@ -7,7 +7,6 @@ import { logger } from "../logger"; import { ExtensionInstance, ExtensionSpec, Param } from "./types"; import { getFirebaseProjectParams, substituteParams } from "./extensionsHelper"; import * as askUserForParam from "./askUserForParam"; -import { track } from "../track"; import * as env from "../functions/env"; import { cloneDeep } from "../utils"; @@ -111,8 +110,6 @@ export async function getParams(args: { reconfiguring: !!args.reconfiguring, }); } - const paramNames = Object.keys(params); - void track("Extension Params", paramNames.length ? "Not Present" : "Present", paramNames.length); return params; } @@ -137,8 +134,6 @@ export async function getParamsForUpdate(args: { instanceId: args.instanceId, }); } - const paramNames = Object.keys(params); - void track("Extension Params", paramNames.length ? "Not Present" : "Present", paramNames.length); return params; } diff --git a/src/test/deploy/hosting/prepare.spec.ts b/src/test/deploy/hosting/prepare.spec.ts index c8041ad9aba..4ddb7b661a0 100644 --- a/src/test/deploy/hosting/prepare.spec.ts +++ b/src/test/deploy/hosting/prepare.spec.ts @@ -104,7 +104,9 @@ describe("hosting prepare", () => { }; await prepare(context, options); - expect(trackingStub.track).to.have.been.calledOnceWith("hosting_deploy", "fake-framework"); + expect(trackingStub.trackGA4).to.have.been.calledOnceWith("hosting_version", { + framework: "fake-framework", + }); expect(hostingStub.createVersion).to.have.been.calledOnce; expect(context.hosting).to.deep.equal({ deploys: [ @@ -138,7 +140,9 @@ describe("hosting prepare", () => { }; await prepare(context, options); - expect(trackingStub.track).to.have.been.calledOnceWith("hosting_deploy", "classic"); + expect(trackingStub.trackGA4).to.have.been.calledOnceWith("hosting_version", { + framework: "classic", + }); expect(hostingStub.createVersion).to.have.been.calledOnce; expect(context.hosting).to.deep.equal({ deploys: [ diff --git a/src/track.ts b/src/track.ts index 65d3bcdd817..c1aa68eaf33 100644 --- a/src/track.ts +++ b/src/track.ts @@ -7,11 +7,36 @@ import { configstore } from "./configstore"; import { logger } from "./logger"; const pkg = require("../package.json"); -// The ID identifying the GA4 property for the Emulator Suite only. Should only -// be used in Emulator UI and emulator-related commands (e.g. emulators:start). -export const EMULATOR_GA4_MEASUREMENT_ID = - process.env.FIREBASE_EMULATOR_GA4_MEASUREMENT_ID || "G-KYP2JMPFC0"; - +type cliEventNames = + | "command_execution" + | "product_deploy" + | "error" + | "login" + | "api_enabled" + | "hosting_version" + | "extension_added_to_manifest"; +type GA4Property = "cli" | "emulator"; +interface GA4Info { + measurementId: string; + apiSecret: string; + clientIdKey: string; + currentSession?: AnalyticsSession; +} +export const GA4_PROPERTIES: Record = { + // Info for the GA4 property for the rest of the CLI. + cli: { + measurementId: process.env.FIREBASE_CLI_GA4_MEASUREMENT_ID || "G-PDN0QWHQJR", + apiSecret: process.env.FIREBASE_CLI_GA4_API_SECRET || "LSw5lNxhSFSWeB6aIzJS2w", + clientIdKey: "analytics-uuid", + }, + // Info for the GA4 property for the Emulator Suite only. Should only + // be used in Emulator UI and emulator-related commands (e.g. emulators:start). + emulator: { + measurementId: process.env.FIREBASE_EMULATOR_GA4_MEASUREMENT_ID || "G-KYP2JMPFC0", + apiSecret: process.env.FIREBASE_EMULATOR_GA4_API_SECRET || "2V_zBYc4TdeoppzDaIu0zw", + clientIdKey: "emulator-analytics-clientId", + }, +}; /** * UA is enabled only if: * 1) Entrypoint to the code is Firebase CLI (not require("firebase-tools")). @@ -21,55 +46,9 @@ export function usageEnabled(): boolean { return !!process.env.IS_FIREBASE_CLI && !!configstore.get("usage"); } -// The Tracking ID for the Universal Analytics property for all of the CLI -// including emulator-related commands (double-tracked for historical reasons) -// but excluding Emulator UI. -// TODO: Upgrade to GA4 before July 1, 2023. See: -// https://support.google.com/analytics/answer/11583528 -const FIREBASE_ANALYTICS_UA = process.env.FIREBASE_ANALYTICS_UA || "UA-29174744-3"; - -let visitor: ua.Visitor; - -function ensureUAVisitor(): void { - if (!visitor) { - // Identifier for the client (UUID) in the CLI UA. - let anonId = configstore.get("analytics-uuid") as string; - if (!anonId) { - anonId = uuidV4(); - configstore.set("analytics-uuid", anonId); - } - - visitor = ua(FIREBASE_ANALYTICS_UA, anonId, { - strictCidFormat: false, - https: true, - }); - - visitor.set("cd1", process.platform); // Platform - visitor.set("cd2", process.version); // NodeVersion - visitor.set("cd3", process.env.FIREPIT_VERSION || "none"); // FirepitVersion - } -} - -export function track(action: string, label: string, duration = 0): Promise { - ensureUAVisitor(); - return new Promise((resolve) => { - if (usageEnabled() && configstore.get("tokens")) { - visitor.event("Firebase CLI " + pkg.version, action, label, duration).send(() => { - // we could handle errors here, but we won't - resolve(); - }); - } else { - resolve(); - } - }); -} - -const EMULATOR_GA4_API_SECRET = - process.env.FIREBASE_EMULATOR_GA4_API_SECRET || "2V_zBYc4TdeoppzDaIu0zw"; - // Prop name length must <= 24 and cannot begin with google_/ga_/firebase_. // https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=firebase#reserved_parameter_names -const EMULATOR_GA4_USER_PROPS = { +const GA4_USER_PROPS = { node_platform: { value: process.platform, }, @@ -97,6 +76,11 @@ export interface AnalyticsParams { /** The elapsed time in milliseconds (e.g. for command runs) (param for custom metrics) */ duration?: number; + /** The result (success or error) of a command */ + result?: string; + + /** Whether the command was run in interactive or noninteractive mode */ + interactive?: string; /** * One-off params (that may be used for custom params / metrics later). * @@ -110,6 +94,24 @@ export interface AnalyticsParams { [key: string]: string | number | undefined; } +export async function trackGA4( + eventName: cliEventNames, + params: AnalyticsParams, + duration: number = 1 // Default to 1ms duration so that events show up in realtime view. +): Promise { + const session = cliSession(); + if (!session) { + return; + } + return _ga4Track({ + session, + apiSecret: GA4_PROPERTIES.cli.apiSecret, + eventName, + params, + duration, + }); +} + /** * Record an emulator-related event for Analytics. * @@ -134,11 +136,29 @@ export async function trackEmulator(eventName: string, params?: AnalyticsParams) // staring at the terminal and waiting for the command to finish also counts.) const oldTotalEngagementSeconds = session.totalEngagementSeconds; session.totalEngagementSeconds = process.uptime(); + const duration = session.totalEngagementSeconds - oldTotalEngagementSeconds; + return _ga4Track({ + session, + apiSecret: GA4_PROPERTIES.emulator.apiSecret, + eventName, + params, + duration, + }); +} + +async function _ga4Track(args: { + session: AnalyticsSession; + apiSecret: string; + eventName: string; + params?: AnalyticsParams; + duration?: number; +}): Promise { + const { session, apiSecret, eventName, params, duration } = args; // Memorize and set command_name throughout the session. session.commandName = params?.command_name || session.commandName; - const search = `?api_secret=${EMULATOR_GA4_API_SECRET}&measurement_id=${session.measurementId}`; + const search = `?api_secret=${apiSecret}&measurement_id=${session.measurementId}`; const validate = session.validateOnly ? "debug/" : ""; const url = `https://www.google-analytics.com/${validate}mp/collect${search}`; const body = { @@ -147,7 +167,7 @@ export async function trackEmulator(eventName: string, params?: AnalyticsParams) timestamp_micros: `${Date.now()}000`, client_id: session.clientId, user_properties: { - ...EMULATOR_GA4_USER_PROPS, + ...GA4_USER_PROPS, java_major_version: session.javaMajorVersion ? { value: session.javaMajorVersion } : undefined, @@ -165,10 +185,7 @@ export async function trackEmulator(eventName: string, params?: AnalyticsParams) // https://support.google.com/analytics/answer/11109416?hl=en // Additional engagement time since last event, in microseconds. - engagement_time_msec: (session.totalEngagementSeconds - oldTotalEngagementSeconds) - .toFixed(3) - .replace(".", "") - .replace(/^0+/, ""), // trim leading zeros + engagement_time_msec: (duration ?? 0).toFixed(3).replace(".", "").replace(/^0+/, ""), // trim leading zeros // https://support.google.com/analytics/answer/7201382?hl=en // To turn debug mode off, `debug_mode` must be left out not `false`. @@ -180,7 +197,11 @@ export async function trackEmulator(eventName: string, params?: AnalyticsParams) ], }; if (session.validateOnly) { - logger.info(`Sending Analytics for event ${eventName}`, params, body); + logger.info( + `Sending Analytics for event ${eventName} to property ${session.measurementId}`, + params, + body + ); } try { const response = await fetch(url, { @@ -240,6 +261,14 @@ export interface AnalyticsSession { } export function emulatorSession(): AnalyticsSession | undefined { + return session("emulator"); +} + +export function cliSession(): AnalyticsSession | undefined { + return session("cli"); +} + +function session(propertyName: GA4Property): AnalyticsSession | undefined { const validateOnly = !!process.env.FIREBASE_CLI_MP_VALIDATE; if (!usageEnabled()) { if (validateOnly) { @@ -247,15 +276,15 @@ export function emulatorSession(): AnalyticsSession | undefined { } return; } - if (!currentEmulatorSession) { - let clientId: string | undefined = configstore.get("emulator-analytics-clientId"); + const property = GA4_PROPERTIES[propertyName]; + if (!property.currentSession) { + let clientId: string | undefined = configstore.get(property.clientIdKey); if (!clientId) { clientId = uuidV4(); - configstore.set("emulator-analytics-clientId", clientId); + configstore.set(property.clientIdKey, clientId); } - - currentEmulatorSession = { - measurementId: EMULATOR_GA4_MEASUREMENT_ID, + property.currentSession = { + measurementId: property.measurementId, clientId, // This must be an int64 string, but only ~50 bits are generated here @@ -268,11 +297,9 @@ export function emulatorSession(): AnalyticsSession | undefined { validateOnly, }; } - return currentEmulatorSession; + return property.currentSession; } -let currentEmulatorSession: AnalyticsSession | undefined = undefined; - function isDebugMode(): boolean { const account = getGlobalDefaultAccount(); if (account?.user.email.endsWith("@google.com")) { @@ -289,3 +316,46 @@ function isDebugMode(): boolean { } return false; } + +// The Tracking ID for the Universal Analytics property for all of the CLI +// including emulator-related commands (double-tracked for historical reasons) +// but excluding Emulator UI. +// TODO: Upgrade to GA4 before July 1, 2023. See: +// https://support.google.com/analytics/answer/11583528 +const FIREBASE_ANALYTICS_UA = process.env.FIREBASE_ANALYTICS_UA || "UA-29174744-3"; + +let visitor: ua.Visitor; + +function ensureUAVisitor(): void { + if (!visitor) { + // Identifier for the client (UUID) in the CLI UA. + let anonId = configstore.get("analytics-uuid") as string; + if (!anonId) { + anonId = uuidV4(); + configstore.set("analytics-uuid", anonId); + } + + visitor = ua(FIREBASE_ANALYTICS_UA, anonId, { + strictCidFormat: false, + https: true, + }); + + visitor.set("cd1", process.platform); // Platform + visitor.set("cd2", process.version); // NodeVersion + visitor.set("cd3", process.env.FIREPIT_VERSION || "none"); // FirepitVersion + } +} + +export function track(action: string, label: string, duration = 0): Promise { + ensureUAVisitor(); + return new Promise((resolve) => { + if (usageEnabled() && configstore.get("tokens")) { + visitor.event("Firebase CLI " + pkg.version, action, label, duration).send(() => { + // we could handle errors here, but we won't + resolve(); + }); + } else { + resolve(); + } + }); +} From a9b6ecfe2744294be34f5113f01cd7edf9fa3918 Mon Sep 17 00:00:00 2001 From: clairekeer1997 Date: Thu, 22 Jun 2023 17:38:52 -0700 Subject: [PATCH 077/320] Release Firestore emulator 1.18.1 (#5942) * Release Firestore emulator 1.18.1 * Update CHANGELOG.md Co-authored-by: joehan * Formatting changes in CHANGE.md * Update CHANGELOG.md --------- Co-authored-by: Jia You Co-authored-by: joehan Co-authored-by: christhompsongoogle <106194718+christhompsongoogle@users.noreply.github.com> --- CHANGELOG.md | 1 + src/emulator/downloadableEmulators.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c93ac2e5b19..65ff9f56488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,3 @@ +- Release Firestore emulator 1.18.1 which addes a emulator configuration to start with experimental mode (#5942). - Run lifecycle hooks for specific codebases. (#6011) - Fixed issue causing `firebase emulators:start` to crash in Next.js apps (#6005) diff --git a/src/emulator/downloadableEmulators.ts b/src/emulator/downloadableEmulators.ts index 072fb699a58..ca3ec53dbe8 100644 --- a/src/emulator/downloadableEmulators.ts +++ b/src/emulator/downloadableEmulators.ts @@ -33,9 +33,9 @@ const EMULATOR_UPDATE_DETAILS: { [s in DownloadableEmulators]: EmulatorUpdateDet expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63", }, firestore: { - version: "1.17.4", - expectedSize: 64969580, - expectedChecksum: "9d580b58e55e57b0cdc3ca8888098d43", + version: "1.18.1", + expectedSize: 64866257, + expectedChecksum: "743211a3e33217fe71dc20aff1fa26a5", }, storage: { version: "1.1.3", From 29747a824caa5589a4e04851a4ca0fa92491f03e Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Fri, 23 Jun 2023 10:18:06 -0700 Subject: [PATCH 078/320] Fix frameworks deploy to preview channel (#6025) --- src/deploy/hosting/prepare.ts | 7 +++++++ src/frameworks/index.ts | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/deploy/hosting/prepare.ts b/src/deploy/hosting/prepare.ts index 0a6223c39bf..5cff13ae002 100644 --- a/src/deploy/hosting/prepare.ts +++ b/src/deploy/hosting/prepare.ts @@ -12,6 +12,7 @@ import * as utils from "../../utils"; import { HostingSource, RunRewrite } from "../../firebaseConfig"; import * as backend from "../functions/backend"; import { ensureTargeted } from "../../functions/ensureTargeted"; +import { generateSSRCodebaseId } from "../../frameworks"; function handlePublicDirectoryFlag(options: HostingOptions & Options): void { // Allow the public directory to be overridden by the --public flag @@ -74,6 +75,12 @@ export async function addPinnedFunctionsToOnlyString( ]?.[r.function.functionId]; if (endpoint) { options.only = ensureTargeted(options.only, endpoint.codebase || "default", endpoint.id); + } else if (c.webFramework) { + options.only = ensureTargeted( + options.only, + generateSSRCodebaseId(c.site), + r.function.functionId + ); } else { // This endpoint is just being added in this push. We don't know what codebase it is. options.only = ensureTargeted(options.only, r.function.functionId); diff --git a/src/frameworks/index.ts b/src/frameworks/index.ts index 8ac1b3bf9c8..b25bc4f49b3 100644 --- a/src/frameworks/index.ts +++ b/src/frameworks/index.ts @@ -104,6 +104,14 @@ function memoizeBuild( return value; } +/** + * Use a function to ensure the same codebase name is used here and + * during hosting deploy. + */ +export function generateSSRCodebaseId(site: string) { + return `firebase-frameworks-${site}`; +} + /** * */ @@ -330,7 +338,7 @@ export async function prepareFrameworks( ); } - const codebase = `firebase-frameworks-${site}`; + const codebase = generateSSRCodebaseId(site); const existingFunctionsConfig = options.config.get("functions") ? [].concat(options.config.get("functions")) : []; From d971a08f4be53066f5240483c8725cc632d6c4cb Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Fri, 23 Jun 2023 11:08:40 -0700 Subject: [PATCH 079/320] Inject GOOGLE_CLOUD_QUOTA_PROJECT environment variable during function discovery and emulation (#5985) When deploying functions that makes use of GCP's usage-based (not resource-based) APIs , such as Vertex AI or ML Vision API, users may see an error like this: ``` // main.py import vertexai # Initialize the Vertex AI client vertexai.init() $ firebase deploy Failed to load function definition from source: FirebaseError: Failed to parse build specification Caused by: 403 Vertex AI API has not been used in project 563584335869 before or it is disabled. ``` During function discovery, `vertex.init()` makes a call to the Vertex AI with the client credentials associated with Firebase CLI . In the case of usage-based APIs, the call is being made on the Firebase CLI project, not the users project, resulting in the error message like `been used in project 563584335869 before or it is disabled.` (project `563584335869` is the Firebase CLI GCP project). Similar issue happens when running the function on the emulator. To workaround the issue, we have to properly override the client project associated with the Vertex AI API call. There are few ways for doing this, and here we choose to leverage `GOOGLE_CLOUD_QUOTA_PROJECT` environment variable to correctly override the quota project to be the user project associated with the Firebase CLI session. --- src/deploy/functions/prepare.ts | 8 +++++++- src/emulator/functionsEmulator.ts | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/deploy/functions/prepare.ts b/src/deploy/functions/prepare.ts index 38f22c88675..d666ccac1db 100644 --- a/src/deploy/functions/prepare.ts +++ b/src/deploy/functions/prepare.ts @@ -457,7 +457,13 @@ export async function loadCodebases( await runtimeDelegate.build(); const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId); - wantBuilds[codebase] = await runtimeDelegate.discoverBuild(runtimeConfig, firebaseEnvs); + wantBuilds[codebase] = await runtimeDelegate.discoverBuild(runtimeConfig, { + ...firebaseEnvs, + // Quota project is required when using GCP's Client-based APIs + // Some GCP client SDKs, like Vertex AI, requires appropriate quota project setup + // in order for .init() calls to succeed. + GOOGLE_CLOUD_QUOTA_PROJECT: projectId, + }); } return wantBuilds; } diff --git a/src/emulator/functionsEmulator.ts b/src/emulator/functionsEmulator.ts index a3f93206585..3d753ec2d68 100644 --- a/src/emulator/functionsEmulator.ts +++ b/src/emulator/functionsEmulator.ts @@ -1167,6 +1167,9 @@ export class FunctionsEmulator implements EmulatorInstance { envs.GCLOUD_PROJECT = this.args.projectId; envs.K_REVISION = "1"; envs.PORT = "80"; + // Quota project is required when using GCP's Client-based APIs. + // Some GCP client SDKs, like Vertex AI, requires appropriate quota project setup. + envs.GOOGLE_CLOUD_QUOTA_PROJECT = this.args.projectId; if (trigger) { const target = trigger.entryPoint; From 463e6491faed709bc62b1a1778d477aced9caee0 Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Fri, 23 Jun 2023 12:25:26 -0600 Subject: [PATCH 080/320] Reimplement Storage emulator /internal/setRules (#6014) * stash * commit * commit * lint * fix tests * const --- .../internal/tests.ts | 168 ++++++++++++++++++ .../rules/manager.test.ts | 60 +++++-- scripts/storage-emulator-integration/run.sh | 2 + src/emulator/storage/index.ts | 9 +- src/emulator/storage/rules/manager.ts | 4 - src/emulator/storage/server.ts | 101 ++++++++++- 6 files changed, 319 insertions(+), 25 deletions(-) create mode 100644 scripts/storage-emulator-integration/internal/tests.ts diff --git a/scripts/storage-emulator-integration/internal/tests.ts b/scripts/storage-emulator-integration/internal/tests.ts new file mode 100644 index 00000000000..fdf93440650 --- /dev/null +++ b/scripts/storage-emulator-integration/internal/tests.ts @@ -0,0 +1,168 @@ +import { expect } from "chai"; +import * as supertest from "supertest"; +import { StorageRulesFiles } from "../../../src/test/emulators/fixtures"; +import { TriggerEndToEndTest } from "../../integration-helpers/framework"; +import { + EMULATORS_SHUTDOWN_DELAY_MS, + getStorageEmulatorHost, + readEmulatorConfig, + TEST_SETUP_TIMEOUT, +} from "../utils"; + +const FIREBASE_PROJECT = process.env.FBTOOLS_TARGET_PROJECT || "fake-project-id"; +const EMULATOR_CONFIG = readEmulatorConfig(); +const STORAGE_EMULATOR_HOST = getStorageEmulatorHost(EMULATOR_CONFIG); + +describe("Storage emulator internal endpoints", () => { + let test: TriggerEndToEndTest; + + before(async function (this) { + this.timeout(TEST_SETUP_TIMEOUT); + process.env.STORAGE_EMULATOR_HOST = STORAGE_EMULATOR_HOST; + test = new TriggerEndToEndTest(FIREBASE_PROJECT, __dirname, EMULATOR_CONFIG); + await test.startEmulators(["--only", "auth,storage"]); + }); + + beforeEach(async () => { + // Reset emulator to default rules. + await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [StorageRulesFiles.readWriteIfAuth], + }, + }) + .expect(200); + }); + + after(async function (this) { + this.timeout(EMULATORS_SHUTDOWN_DELAY_MS); + delete process.env.STORAGE_EMULATOR_HOST; + await test.stopEmulators(); + }); + + describe("setRules", () => { + it("should set single ruleset", async () => { + await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [StorageRulesFiles.readWriteIfTrue], + }, + }) + .expect(200); + }); + + it("should set multiple rules/resource objects", async () => { + await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [ + { resource: "bucket_0", ...StorageRulesFiles.readWriteIfTrue }, + { resource: "bucket_1", ...StorageRulesFiles.readWriteIfAuth }, + ], + }, + }) + .expect(200); + }); + + it("should overwrite single ruleset with multiple rules/resource objects", async () => { + await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [StorageRulesFiles.readWriteIfTrue], + }, + }) + .expect(200); + + await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [ + { resource: "bucket_0", ...StorageRulesFiles.readWriteIfTrue }, + { resource: "bucket_1", ...StorageRulesFiles.readWriteIfAuth }, + ], + }, + }) + .expect(200); + }); + + it("should return 400 if rules.files array is missing", async () => { + const errorMessage = await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ rules: {} }) + .expect(400) + .then((res) => res.body.message); + + expect(errorMessage).to.equal("Request body must include 'rules.files' array"); + }); + + it("should return 400 if rules.files array has missing name field", async () => { + const errorMessage = await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [{ content: StorageRulesFiles.readWriteIfTrue.content }], + }, + }) + .expect(400) + .then((res) => res.body.message); + + expect(errorMessage).to.equal( + "Each member of 'rules.files' array must contain 'name' and 'content'" + ); + }); + + it("should return 400 if rules.files array has missing content field", async () => { + const errorMessage = await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [{ name: StorageRulesFiles.readWriteIfTrue.name }], + }, + }) + .expect(400) + .then((res) => res.body.message); + + expect(errorMessage).to.equal( + "Each member of 'rules.files' array must contain 'name' and 'content'" + ); + }); + + it("should return 400 if rules.files array has missing resource field", async () => { + const errorMessage = await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [ + { resource: "bucket_0", ...StorageRulesFiles.readWriteIfTrue }, + StorageRulesFiles.readWriteIfAuth, + ], + }, + }) + .expect(400) + .then((res) => res.body.message); + + expect(errorMessage).to.equal( + "Each member of 'rules.files' array must contain 'name', 'content', and 'resource'" + ); + }); + + it("should return 400 if rules.files array has invalid content", async () => { + const errorMessage = await supertest(STORAGE_EMULATOR_HOST) + .put("/internal/setRules") + .send({ + rules: { + files: [{ name: StorageRulesFiles.readWriteIfTrue.name, content: "foo" }], + }, + }) + .expect(400) + .then((res) => res.body.message); + + expect(errorMessage).to.equal("There was an error updating rules, see logs for more details"); + }); + }); +}); diff --git a/scripts/storage-emulator-integration/rules/manager.test.ts b/scripts/storage-emulator-integration/rules/manager.test.ts index d483cf1ec61..cc0ef2b9e23 100644 --- a/scripts/storage-emulator-integration/rules/manager.test.ts +++ b/scripts/storage-emulator-integration/rules/manager.test.ts @@ -1,10 +1,7 @@ import { expect } from "chai"; import { createTmpDir, StorageRulesFiles } from "../../../src/test/emulators/fixtures"; -import { - createStorageRulesManager, - StorageRulesManager, -} from "../../../src/emulator/storage/rules/manager"; +import { createStorageRulesManager } from "../../../src/emulator/storage/rules/manager"; import { StorageRulesRuntime } from "../../../src/emulator/storage/rules/runtime"; import * as fs from "fs"; import { RulesetOperationMethod, SourceFile } from "../../../src/emulator/storage/rules/types"; @@ -14,22 +11,21 @@ import * as path from "path"; const EMULATOR_LOAD_RULESET_DELAY_MS = 20000; const SETUP_TIMEOUT = 60000; +const PROJECT_ID = "demo-project-id"; describe("Storage Rules Manager", () => { let rulesRuntime: StorageRulesRuntime; const opts = { method: RulesetOperationMethod.GET, file: {}, path: "/b/bucket_0/o/" }; - const projectId = "demo-project-id"; - let rulesManager: StorageRulesManager; - beforeEach(async function (this) { + before(async function (this) { this.timeout(SETUP_TIMEOUT); rulesRuntime = new StorageRulesRuntime(); await rulesRuntime.start(); }); - afterEach(async function (this) { + after(async function (this) { this.timeout(SETUP_TIMEOUT); - await rulesManager.stop(); + await rulesRuntime.stop(); }); it("should load multiple rulesets on start", async function (this) { @@ -38,18 +34,30 @@ describe("Storage Rules Manager", () => { { resource: "bucket_0", rules: StorageRulesFiles.readWriteIfTrue }, { resource: "bucket_1", rules: StorageRulesFiles.readWriteIfAuth }, ]; - rulesManager = createStorageRulesManager(rules, rulesRuntime); + const rulesManager = createStorageRulesManager(rules, rulesRuntime); await rulesManager.start(); const bucket0Ruleset = rulesManager.getRuleset("bucket_0"); expect( - await isPermitted({ ...opts, path: "/b/bucket_0/o/", ruleset: bucket0Ruleset!, projectId }) + await isPermitted({ + ...opts, + path: "/b/bucket_0/o/", + ruleset: bucket0Ruleset!, + projectId: PROJECT_ID, + }) ).to.be.true; const bucket1Ruleset = rulesManager.getRuleset("bucket_1"); expect( - await isPermitted({ ...opts, path: "/b/bucket_1/o/", ruleset: bucket1Ruleset!, projectId }) + await isPermitted({ + ...opts, + path: "/b/bucket_1/o/", + ruleset: bucket1Ruleset!, + projectId: PROJECT_ID, + }) ).to.be.false; + + await rulesManager.stop(); }); it("should load single ruleset on start", async function (this) { @@ -60,11 +68,13 @@ describe("Storage Rules Manager", () => { appendBytes(testDir, fileName, Buffer.from(StorageRulesFiles.readWriteIfTrue.content)); const sourceFile = getSourceFile(testDir, fileName); - rulesManager = createStorageRulesManager(sourceFile, rulesRuntime); + const rulesManager = createStorageRulesManager(sourceFile, rulesRuntime); await rulesManager.start(); const ruleset = rulesManager.getRuleset("bucket"); - expect(await isPermitted({ ...opts, ruleset: ruleset!, projectId })).to.be.true; + expect(await isPermitted({ ...opts, ruleset: ruleset!, projectId: PROJECT_ID })).to.be.true; + + await rulesManager.stop(); }); it("should reload ruleset on changes to source file", async function (this) { @@ -75,19 +85,31 @@ describe("Storage Rules Manager", () => { appendBytes(testDir, fileName, Buffer.from(StorageRulesFiles.readWriteIfTrue.content)); const sourceFile = getSourceFile(testDir, fileName); - rulesManager = createStorageRulesManager(sourceFile, rulesRuntime); + const rulesManager = createStorageRulesManager(sourceFile, rulesRuntime); await rulesManager.start(); - expect(await isPermitted({ ...opts, ruleset: rulesManager.getRuleset("bucket")!, projectId })) - .to.be.true; + expect( + await isPermitted({ + ...opts, + ruleset: rulesManager.getRuleset("bucket")!, + projectId: PROJECT_ID, + }) + ).to.be.true; // Write new rules to file deleteFile(testDir, fileName); appendBytes(testDir, fileName, Buffer.from(StorageRulesFiles.readWriteIfAuth.content)); await new Promise((resolve) => setTimeout(resolve, EMULATOR_LOAD_RULESET_DELAY_MS)); - expect(await isPermitted({ ...opts, ruleset: rulesManager.getRuleset("bucket")!, projectId })) - .to.be.false; + expect( + await isPermitted({ + ...opts, + ruleset: rulesManager.getRuleset("bucket")!, + projectId: PROJECT_ID, + }) + ).to.be.false; + + await rulesManager.stop(); }); }); diff --git a/scripts/storage-emulator-integration/run.sh b/scripts/storage-emulator-integration/run.sh index 48f3a21a77c..f2152963321 100755 --- a/scripts/storage-emulator-integration/run.sh +++ b/scripts/storage-emulator-integration/run.sh @@ -10,6 +10,8 @@ source scripts/set-default-credentials.sh # Prepare the storage emulator rules runtime firebase setup:emulators:storage +mocha scripts/storage-emulator-integration/internal/tests.ts + mocha scripts/storage-emulator-integration/rules/*.test.ts mocha scripts/storage-emulator-integration/import/tests.ts diff --git a/src/emulator/storage/index.ts b/src/emulator/storage/index.ts index cadb34c61a0..d57dc3e8758 100644 --- a/src/emulator/storage/index.ts +++ b/src/emulator/storage/index.ts @@ -6,7 +6,7 @@ import { createApp } from "./server"; import { StorageLayer, StoredFile } from "./files"; import { EmulatorLogger } from "../emulatorLogger"; import { createStorageRulesManager, StorageRulesManager } from "./rules/manager"; -import { StorageRulesRuntime } from "./rules/runtime"; +import { StorageRulesIssues, StorageRulesRuntime } from "./rules/runtime"; import { SourceFile } from "./rules/types"; import * as express from "express"; import { @@ -118,6 +118,7 @@ export class StorageEmulator implements EmulatorInstance { async stop(): Promise { await this._persistence.deleteAll(); + await this._rulesRuntime.stop(); await this._rulesManager.stop(); return this.destroyServer ? this.destroyServer() : Promise.resolve(); } @@ -145,6 +146,12 @@ export class StorageEmulator implements EmulatorInstance { return createStorageRulesManager(rules, this._rulesRuntime); } + async replaceRules(rules: SourceFile | RulesConfig[]): Promise { + await this._rulesManager.stop(); + this._rulesManager = this.createRulesManager(rules); + return this._rulesManager.start(); + } + private getPersistenceTmpDir(): string { return `${tmpdir()}/firebase/storage/blobs`; } diff --git a/src/emulator/storage/rules/manager.ts b/src/emulator/storage/rules/manager.ts index 9c4d8cd8526..53d292196f9 100644 --- a/src/emulator/storage/rules/manager.ts +++ b/src/emulator/storage/rules/manager.ts @@ -60,7 +60,6 @@ class DefaultStorageRulesManager implements StorageRulesManager { } async start(): Promise { - this._runtime.start(); const issues = await this.loadRuleset(); this.updateWatcher(this._rules.name); return issues; @@ -72,9 +71,6 @@ class DefaultStorageRulesManager implements StorageRulesManager { async stop(): Promise { await this._watcher.close(); - if (this._runtime.alive) { - await this._runtime.stop(); - } } private updateWatcher(rulesFile: string): void { diff --git a/src/emulator/storage/server.ts b/src/emulator/storage/server.ts index d5e82e53ac4..1489f5fb09f 100644 --- a/src/emulator/storage/server.ts +++ b/src/emulator/storage/server.ts @@ -4,8 +4,10 @@ import { EmulatorLogger } from "../emulatorLogger"; import { Emulators } from "../types"; import * as bodyParser from "body-parser"; import { createCloudEndpoints } from "./apis/gcloud"; -import { StorageEmulator } from "./index"; +import { RulesConfig, StorageEmulator } from "./index"; import { createFirebaseEndpoints } from "./apis/firebase"; +import { InvalidArgumentError } from "../auth/errors"; +import { SourceFile } from "./rules/types"; /** * @param defaultProjectId @@ -77,6 +79,91 @@ export function createApp( res.sendStatus(200); }); + /** + * Internal endpoint to overwrite current rules. Callers provide either a single set of rules to + * be applied to all resources or an array of rules/resource objects. + * + * Example payload for single set of rules: + * + * ``` + * { + * rules: { + * files: [{ name: , content: }] + * } + * } + * ``` + * + * Example payload for multiple rules/resource objects: + * + * ``` + * { + * rules: { + * files: [ + * { name: , content: , resource: }, + * ... + * ] + * } + * } + * ``` + */ + app.put("/internal/setRules", async (req, res) => { + const rulesRaw = req.body.rules; + if (!(rulesRaw && Array.isArray(rulesRaw.files) && rulesRaw.files.length > 0)) { + res.status(400).json({ + message: "Request body must include 'rules.files' array", + }); + return; + } + + const { files } = rulesRaw; + + function parseRulesFromFiles(files: Array): SourceFile | RulesConfig[] { + if (files.length === 1) { + const file = files[0]; + if (!isRulesFile(file)) { + throw new InvalidArgumentError( + "Each member of 'rules.files' array must contain 'name' and 'content'" + ); + } + return { name: file.name, content: file.content }; + } + + const rules: RulesConfig[] = []; + for (const file of files) { + if (!isRulesFile(file) || !file.resource) { + throw new InvalidArgumentError( + "Each member of 'rules.files' array must contain 'name', 'content', and 'resource'" + ); + } + rules.push({ resource: file.resource, rules: { name: file.name, content: file.content } }); + } + return rules; + } + + let rules: SourceFile | RulesConfig[]; + try { + rules = parseRulesFromFiles(files); + } catch (err) { + if (err instanceof InvalidArgumentError) { + res.status(400).json({ message: err.message }); + return; + } + throw err; + } + + const issues = await emulator.replaceRules(rules); + if (issues.errors.length > 0) { + res.status(400).json({ + message: "There was an error updating rules, see logs for more details", + }); + return; + } + + res.status(200).json({ + message: "Rules updated successfully", + }); + }); + app.post("/internal/reset", (req, res) => { emulator.reset(); res.sendStatus(200); @@ -87,3 +174,15 @@ export function createApp( return Promise.resolve(app); } + +interface RulesFile { + name: string; + content: string; + resource?: string; +} + +function isRulesFile(file: unknown): file is RulesFile { + return ( + typeof (file as RulesFile).name === "string" && typeof (file as RulesFile).content === "string" + ); +} From 8af4c93aa26ed5ea3c59fb572a94316469d3f4aa Mon Sep 17 00:00:00 2001 From: joehan Date: Fri, 23 Jun 2023 11:36:18 -0700 Subject: [PATCH 081/320] Adding JSON schema for extension yaml (#5984) * Starting on extension.yaml json schema * finsh extension.yaml schema * adding events * add billingrequired * Adding schemas to vscode plugin too * reverting new format for firebase-config.json --- firebase-vscode/package.json | 14 +- schema/extension-yaml.json | 432 +++++++++++++++++++++++++++++++++++ 2 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 schema/extension-yaml.json diff --git a/firebase-vscode/package.json b/firebase-vscode/package.json index ad7369c27c9..aa206f8ae34 100644 --- a/firebase-vscode/package.json +++ b/firebase-vscode/package.json @@ -68,7 +68,19 @@ "name": "Firebase" } ] - } + }, + "jsonValidation": [ + { + "fileMatch": "firebase.json", + "url": "https://raw.githubusercontent.com/firebase/firebase-tools/master/schema/firebase-config.json" + } + ], + "yamlValidation": [ + { + "fileMatch": "extension.yaml", + "url": "https://raw.githubusercontent.com/firebase/firebase-tools/master/schema/extension-yaml.json" + } + ] }, "scripts": { "vscode:prepublish": "npm run build", diff --git a/schema/extension-yaml.json b/schema/extension-yaml.json new file mode 100644 index 00000000000..6440c59e937 --- /dev/null +++ b/schema/extension-yaml.json @@ -0,0 +1,432 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "definitions": { + "author": { + "additionalProperties": false, + "type": "object", + "properties": { + "authorName": { + "type": "string", + "description": "The author's name" + }, + "email": { + "type": "string", + "description": "A contact email for the author" + }, + "url": { + "type": "string", + "description": "URL of the author's website" + } + } + }, + "role": { + "additionalProperties": false, + "type": "object", + "description": "An IAM role to grant to this extension.", + "properties": { + "role": { + "type": "string", + "description": "Name of the IAM role to grant. Must be on the list of allowed roles: https://firebase.google.com/docs/extensions/publishers/access#supported-roles", + "pattern": "[a-zA-Z]+\\.[a-zA-Z]+" + }, + "reason": { + "type": "string", + "description": "Why this extension needs this IAM role" + }, + "resource": { + "type": "string", + "description": "What resource to grant this role on. If omitted, defaults to projects/${project_id}" + } + }, + "required": ["role", "reason"] + }, + "api": { + "additionalProperties": false, + "type": "object", + "description": "A Google API used by this extension. Will be enabled on extension deployment.", + "properties": { + "apiName": { + "type": "string", + "description": "Name of the Google API to enable. Should match the service name listed in https://console.cloud.google.com/apis/library", + "pattern": "[^\\.]+\\.googleapis\\.com" + }, + "reason": { + "type": "string", + "description": "Why this extension needs this API enabled" + } + }, + "required": ["apiName", "reason"] + }, + "externalService": { + "additionalProperties": false, + "type": "object", + "description": "A non-Google API used by this extension", + "properties": { + "name": { + "type": "string", + "description": "Name of the external service" + }, + "pricingUri": { + "type": "string", + "description": "URI to pricing information for the service" + } + } + }, + "param": { + "additionalProperties": false, + "type": "object", + "description": "A parameter that users installing this extension can configure", + "properties": { + "param": { + "type": "string", + "description": "The name of the param. This is how you reference the param in your code" + }, + "label": { + "type": "string", + "description": "Short description for the parameter. Displayed to users when they're prompted for the parameter's value." + }, + "description": { + "type": "string", + "description": "Detailed description for the parameter. Displayed to users when they're prompted for the parameter's value." + }, + "example": { + "type": "string", + "description": "Example value for the parameter." + }, + "validationRegex": { + "type": "string", + "description": "Regular expression for validation of the parameter's user-configured value. Uses Google RE2 syntax." + }, + "validationErrorMessage": { + "type": "string", + "description": "Error message to display if regex validation fails." + }, + "default": { + "type": "string", + "description": "Default value for the parameter if the user leaves the parameter's value blank." + }, + "required": { + "type": "boolean", + "description": "Defines whether the user can submit an empty string when they're prompted for the parameter's value. Defaults to true." + }, + "immutable": { + "type": "boolean", + "description": "Defines whether the user can change the parameter's value after installation (such as if they reconfigure the extension). Defaults to false." + }, + "advanced": { + "type": "boolean", + "description": "Whether this a param for advanced users. When true, only users who choose 'advanced configuration' will see this param." + }, + "type": { + "type": "string", + "description": "The parameter type. Special parameter types might have additional requirements or different UI presentation. See https://firebase.google.com/docs/extensions/reference/extension-yaml#params for more details.", + "pattern": "string|STRING|select|SELECT|multiselect|MULTISELECT|secret|SECRET|selectresource|SELECTRESOURCE" + }, + "resourceType": { + "type": "string", + "description": "The type of resource to prompt the user to select. Provides a special UI treatment for the param.", + "pattern": "storage\\.googleapis\\.com\\/Bucket|firestore\\.googleapis\\.com\\/Database|firebasedatabase\\.googleapis\\.com\\/DatabaseInstance" + }, + "options": { + "type": "array", + "description": "Options for a select or multiselect type param.", + "items": { + "$ref": "#/definitions/paramOption" + } + } + }, + "required": ["param"] + }, + "paramOption": { + "additionalProperties": false, + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "One of the values the user can choose. This is the value you get when you read the parameter value in code." + }, + "label": { + "type": "string", + "description": "Short description of the selectable option. If omitted, defaults to value." + } + }, + "required": ["value"] + }, + "resource":{ + "additionalProperties": false, + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of this resource" + }, + "type": { + "type": "string", + "description": "What type of resource this is. See https://firebase.google.com/docs/extensions/reference/extension-yaml#resources for a full list of options." + }, + "description": { + "type": "string", + "description": "A brief description of what this resource does" + }, + "properties": { + "type": "object", + "description": "The properties of this resource", + "additionalProperties": true, + "properties": { + "location": { + "type": "string", + "description": "The location for this resource" + }, + "entryPoint": { + "type": "string", + "description": "The entry point for a function resource" + }, + "sourceDirectory": { + "type": "string", + "description": "Directory that contains your package.json at its root. The file for your functions source code must be in this directory. Defaults to functions" + }, + "timeout": { + "type": "string", + "description": "A function resources's maximum execution time.", + "pattern": "\\d+s" + }, + "availableMemoryMb": { + "type": "string", + "description": "Amount of memory in MB available for the function.", + "pattern": "\\d+" + }, + "runtime": { + "type": "string", + "description": "Runtime environment for the function. Defaults to the most recent LTS version of node." + }, + "httpsTrigger": { + "type": "object", + "description": "A function triggered by HTTPS calls", + "properties": {} + }, + "eventTrigger": { + "type": "object", + "description": "A function triggered by a background event", + "properties": { + "eventType": { + "type": "string", + "description": "The type of background event to trigger on. See https://firebase.google.com/docs/extensions/publishers/functions#supported for a full list." + }, + "resource": { + "type": "string", + "description": "The name or pattern of the resource to trigger on" + }, + "eventFilters": { + "type": "string", + "description": "Filters that further limit the events to listen to." + }, + "channel": { + "type": "string", + "description": "The name of the channel associated with the trigger in projects/{project}/locations/{location}/channels/{channel} format. If you omit this property, the function will listen for events on the project's default channel." + }, + "triggerRegion": { + "type": "string", + "description": "The trigger will only receive events originating in this region. It can be the same region as the function, a different region or multi-region, or the global region. If not provided, defaults to the same region as the function." + } + }, + "required": ["eventType"] + }, + "scheduleTrigger": { + "type": "object", + "description": "A function triggered at a regular interval by a Cloud Scheduler job", + "properties": { + "schedule": { + "type": "string", + "description": "The frequency at which you want the function to run. Accepts unix-cron (https://cloud.google.com/scheduler/docs/configuring/cron-job-schedules) or App Engine (https://cloud.google.com/appengine/docs/standard/nodejs/scheduling-jobs-with-cron-yaml#defining_the_cron_job_schedule) syntax." + }, + "timeZone": { + "type": "string", + "description": "The time zone in which the schedule will run. Defaults to UTC." + } + }, + "required": ["schedule"] + }, + "taskQueueTrigger": { + "type": "object", + "description": "A function triggered by a Cloud Task", + "properties": {} + }, + "buildConfig": { + "type": "object", + "description": "Build configuration for a gen 2 Cloud Function", + "properties": { + "runtime": { + "type": "string", + "description": "Runtime environment for the function. Defaults to the most recent LTS version of node." + }, + "entryPoint": { + "type": "string", + "description": "The entry point for a function resource" + } + } + }, + "serviceConfig": { + "type": "object", + "description": "Service configuration for a gen 2 Cloud Function", + "properties": { + "timeoutSeconds": { + "type": "string", + "description": "The function's maximum execution time. Default: 60, max value: 540." + }, + "availableMemory": { + "type": "string", + "description": "The amount of memory available for a function. Defaults to 256M. Supported units are k, M, G, Mi, Gi. If no unit is supplied, the value is interpreted as bytes." + } + } + } + } + } + }, + "required": ["name", "type", "description", "properties"] + }, + "lifecycleEvent": { + "type": "object", + "additionalProperties": false, + "properties": { + "onInstall": { + "$ref": "#/definitions/lifecycleEventSpec" + }, + "onUpdate": { + "$ref": "#/definitions/lifecycleEventSpec" + }, + "onConfigure": { + "$ref": "#/definitions/lifecycleEventSpec" + } + } + }, + "lifecycleEventSpec": { + "type": "object", + "additionalProperties": false, + "properties": { + "function": { + "type": "string", + "description": "Name of the task queue-triggered function that will handle the event. This function must be a taskQueueTriggered function declared in the resources section." + }, + "processingMessage": { + "type": "string", + "description": "Message to display in the Firebase console while the task is in progress." + } + } + }, + "event": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "description": "The type identifier of the event. Construct the identifier out of 3-4 dot-delimited fields: the publisher ID, extension name, and event name fields are required; the version field is recommended. Choose a unique and descriptive event name for each event type you publish." + }, + "description": { + "type": "string", + "description": "A description of the event" + } + } + } + }, + "properties": { + "name": { + "type": "string", + "description": "ID of this extension (ie your-extension-name)" + }, + "version": { + "type": "string", + "description": "Version of this extension. Follows https://semver.org/." + }, + "specVersion": { + "type":"string", + "description": "Version of the extension.yaml spec that this file follows. Currently always 'v1beta'" + }, + "license": { + "type": "string", + "description": "The software license agreement for this extension. Currently, only 'Apache-2.0' is permitted on extensions.dev" + }, + "displayName": { + "type": "string", + "description": "Human readable name for this extension (ie 'Your Extension Name')" + }, + "description": { + "type": "string", + "description": "A one to two sentence description of what this extension does" + }, + "icon": { + "type": "string", + "description": "The file name of this extension's icon" + }, + "billingRequired": { + "type": "boolean", + "description": "Whether this extension requires a billing to be enabled on the project it is installed on" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of tags to help users find your extension in search" + }, + "sourceUrl": { + "type": "string", + "description": "The URL of the GitHub repo hosting this code" + }, + "releaseNotesUrl": { + "type": "string", + "description": "A URL where users can view the full changelog or release notes for this extension" + }, + "author": { + "$ref": "#/definitions/author" + }, + "contributors": { + "type": "array", + "items": { + "$ref": "#/definitions/author" + } + }, + "apis": { + "type": "array", + "items": { + "$ref": "#/definitions/api" + } + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/definitions/role" + } + }, + "externalServices": { + "type": "array", + "items": { + "$ref": "#/definitions/externalService" + } + }, + "params": { + "type": "array", + "items": { + "$ref": "#/definitions/param" + } + }, + "resources": { + "type": "array", + "items": { + "$ref": "#/definitions/resource" + } + }, + "lifecycleEvents": { + "type": "array", + "items": { + "$ref": "#/definitions/lifecycleEvent" + } + }, + "events": { + "type": "array", + "items": { + "$ref": "#/definitions/event" + } + } + } +} From 34f4d953f111db4f8a8479746bee0b44b46d3a35 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Fri, 23 Jun 2023 12:17:31 -0700 Subject: [PATCH 082/320] Set up vscode plugin test flow (#6024) --- firebase-vscode/.gitignore | 1 + firebase-vscode/.vscodeignore | 1 + firebase-vscode/package.json | 2 +- firebase-vscode/src/test/tsconfig.test.json | 11 +++++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 firebase-vscode/src/test/tsconfig.test.json diff --git a/firebase-vscode/.gitignore b/firebase-vscode/.gitignore index 08ccd9d7281..2eb86a66425 100644 --- a/firebase-vscode/.gitignore +++ b/firebase-vscode/.gitignore @@ -2,3 +2,4 @@ dist/ *.scss.d.ts resources/dist +.vscode-test \ No newline at end of file diff --git a/firebase-vscode/.vscodeignore b/firebase-vscode/.vscodeignore index 4dd9a138ef0..42df22e391a 100644 --- a/firebase-vscode/.vscodeignore +++ b/firebase-vscode/.vscodeignore @@ -17,3 +17,4 @@ webpack.*.js ../ *.zip node_modules/ +dist/test/ \ No newline at end of file diff --git a/firebase-vscode/package.json b/firebase-vscode/package.json index aa206f8ae34..415cf731ecb 100644 --- a/firebase-vscode/package.json +++ b/firebase-vscode/package.json @@ -94,7 +94,7 @@ "build": "npm run copyfiles && webpack --config webpack.prod.js --devtool hidden-source-map", "build:extension": "webpack --config webpack.prod.js --config-name extension", "build:sidebar": "npm run copyfiles && webpack --config webpack.prod.js --config-name sidebar", - "pretest": "npm run build && npm run lint", + "pretest": "npm run dev ; npm run lint && tsc -p src/test/tsconfig.test.json", "lint": "eslint src --ext ts", "test": "node ./dist/test/runTest.js" }, diff --git a/firebase-vscode/src/test/tsconfig.test.json b/firebase-vscode/src/test/tsconfig.test.json new file mode 100644 index 00000000000..0b25a4a95f3 --- /dev/null +++ b/firebase-vscode/src/test/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2020", + "lib": ["es2020"], + "outDir": "../../dist/test", + "sourceMap": true, + "rootDir": "./", + "strict": true, + } +} \ No newline at end of file From f6ed7b6e3356e41eb40e8587a8226f51f4e38c8c Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Mon, 26 Jun 2023 03:02:13 -0700 Subject: [PATCH 083/320] Print functions discovery to stdout/error (#5931) * Print functions discovery to stdout/error * More tweaking * lint fixes * Use logger instead of console to work with --json --------- Co-authored-by: Daniel Lee --- src/deploy/functions/prepare.ts | 4 ++ .../functions/runtimes/discovery/index.ts | 19 +++++++- src/deploy/functions/runtimes/node/index.ts | 20 +++++++-- src/deploy/functions/runtimes/python/index.ts | 45 ++++++++----------- 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/deploy/functions/prepare.ts b/src/deploy/functions/prepare.ts index d666ccac1db..32cad037653 100644 --- a/src/deploy/functions/prepare.ts +++ b/src/deploy/functions/prepare.ts @@ -457,6 +457,10 @@ export async function loadCodebases( await runtimeDelegate.build(); const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId); + logLabeledBullet( + "functions", + `Loading and anaylzing source code for codebase ${codebase} to determine what to deploy` + ); wantBuilds[codebase] = await runtimeDelegate.discoverBuild(runtimeConfig, { ...firebaseEnvs, // Quota project is required when using GCP's Client-based APIs diff --git a/src/deploy/functions/runtimes/discovery/index.ts b/src/deploy/functions/runtimes/discovery/index.ts index c8e53268689..9915e588835 100644 --- a/src/deploy/functions/runtimes/discovery/index.ts +++ b/src/deploy/functions/runtimes/discovery/index.ts @@ -13,6 +13,9 @@ import { FirebaseError } from "../../../../error"; export const readFileAsync = promisify(fs.readFile); +/** + * Converts the YAML retrieved from discovery into a Build object for param interpolation. + */ export function yamlToBuild( yaml: any, project: string, @@ -34,6 +37,9 @@ export function yamlToBuild( } } +/** + * Load a Build from a functions.yaml file. + */ export async function detectFromYaml( directory: string, project: string, @@ -56,6 +62,9 @@ export async function detectFromYaml( return yamlToBuild(parsed, project, api.functionsDefaultRegion, runtime); } +/** + * Load a build from a discovery service. + */ export async function detectFromPort( port: number, project: string, @@ -63,7 +72,7 @@ export async function detectFromPort( timeout = 10_000 /* 10s to boot up */ ): Promise { // The result type of fetch isn't exported - let res: { text(): Promise }; + let res: { text(): Promise; status: number }; const timedOut = new Promise((resolve, reject) => { setTimeout(() => { reject(new FirebaseError("User code failed to load. Cannot determine backend specification")); @@ -83,6 +92,14 @@ export async function detectFromPort( } } + if (res.status !== 200) { + const text = await res.text(); + logger.debug(`Got response code ${res.status}; body ${text}`); + throw new FirebaseError( + "Functions codebase could not be analyzed successfully. " + + "It may have a syntax or runtime error" + ); + } const text = await res.text(); logger.debug("Got response from /__/functions.yaml", text); diff --git a/src/deploy/functions/runtimes/node/index.ts b/src/deploy/functions/runtimes/node/index.ts index 92ac00b6d99..a777f57080f 100644 --- a/src/deploy/functions/runtimes/node/index.ts +++ b/src/deploy/functions/runtimes/node/index.ts @@ -200,13 +200,18 @@ export class Delegate { const binPath = path.join(nodeModulesPath, ".bin", "firebase-functions"); if (fileExistsSync(binPath)) { logger.debug(`Found firebase-functions binary at '${binPath}'`); + // Note: We cannot use inherit because we need the stdout/err to be + // omitted in commands that use --json. const childProcess = spawn(binPath, [this.sourceDir], { env, cwd: this.sourceDir, - stdio: [/* stdin=*/ "ignore", /* stdout=*/ "pipe", /* stderr=*/ "inherit"], + stdio: [/* stdin=*/ "ignore", /* stdout=*/ "pipe", /* stderr=*/ "pipe"], }); - childProcess.stdout?.on("data", (chunk) => { - logger.debug(chunk.toString()); + childProcess.stdout?.on("data", (chunk: Buffer) => { + logger.info(chunk.toString("utf8")); + }); + childProcess.stderr?.on("data", (chunk: Buffer) => { + logger.error(chunk.toString("utf8")); }); return Promise.resolve(async () => { const p = new Promise((resolve, reject) => { @@ -214,7 +219,14 @@ export class Delegate { childProcess.once("error", reject); }); - await fetch(`http://localhost:${port}/__/quitquitquit`); + try { + await fetch(`http://localhost:${port}/__/quitquitquit`); + } catch (e) { + logger.debug( + "Failed to call quitquitquit. This often means the server failed to start", + e + ); + } setTimeout(() => { if (!childProcess.killed) { childProcess.kill("SIGKILL"); diff --git a/src/deploy/functions/runtimes/python/index.ts b/src/deploy/functions/runtimes/python/index.ts index e17a9043539..2dfbebbef93 100644 --- a/src/deploy/functions/runtimes/python/index.ts +++ b/src/deploy/functions/runtimes/python/index.ts @@ -12,7 +12,6 @@ import { logger } from "../../../../logger"; import { DEFAULT_VENV_DIR, runWithVirtualEnv, virtualEnvCmd } from "../../../../functions/python"; import { FirebaseError } from "../../../../error"; import { Build } from "../../build"; -import { logLabeledWarning } from "../../../../utils"; export const LATEST_VERSION: runtimes.Runtime = "python311"; @@ -145,8 +144,6 @@ export class Delegate implements runtimes.RuntimeDelegate { ADMIN_PORT: port.toString(), }; const args = [this.bin, `"${path.join(modulesDir, "private", "serving.py")}"`]; - const stdout: string[] = []; - const stderr: string[] = []; logger.debug( `Running admin server with args: ${JSON.stringify(args)} and env: ${JSON.stringify( envWithAdminPort @@ -154,27 +151,27 @@ export class Delegate implements runtimes.RuntimeDelegate { ); const childProcess = runWithVirtualEnv(args, this.sourceDir, envWithAdminPort); childProcess.stdout?.on("data", (chunk: Buffer) => { - const chunkString = chunk.toString(); - stdout.push(chunkString); - logger.debug(`stdout: ${chunkString}`); + logger.info(chunk.toString("utf8")); }); childProcess.stderr?.on("data", (chunk: Buffer) => { - const chunkString = chunk.toString(); - stderr.push(chunkString); - logger.debug(`stderr: ${chunkString}`); + logger.error(chunk.toString("utf8")); }); - return Promise.resolve({ - stderr, - stdout, - killProcess: async () => { + return Promise.resolve(async () => { + try { await fetch(`http://127.0.0.1:${port}/__/quitquitquit`); - const quitTimeout = setTimeout(() => { - if (!childProcess.killed) { - childProcess.kill("SIGKILL"); - } - }, 10_000); - clearTimeout(quitTimeout); - }, + } catch (e) { + logger.debug("Failed to call quitquitquit. This often means the server failed to start", e); + } + const quitTimeout = setTimeout(() => { + if (!childProcess.killed) { + childProcess.kill("SIGKILL"); + } + }, 10_000); + clearTimeout(quitTimeout); + return new Promise((resolve, reject) => { + childProcess.once("exit", resolve); + childProcess.once("error", reject); + }); }); } @@ -187,15 +184,9 @@ export class Delegate implements runtimes.RuntimeDelegate { const adminPort = await portfinder.getPortPromise({ port: 8081, }); - const { killProcess, stderr } = await this.serveAdmin(adminPort, envs); + const killProcess = await this.serveAdmin(adminPort, envs); try { discovered = await discovery.detectFromPort(adminPort, this.projectId, this.runtime); - } catch (e: any) { - logLabeledWarning( - "functions", - `Failed to detect functions from source ${e}.\nstderr:${stderr.join("\n")}` - ); - throw e; } finally { await killProcess(); } From 380390f89f21a0f54f33b4174076a6996c42d4ce Mon Sep 17 00:00:00 2001 From: Alex Astrum Date: Mon, 26 Jun 2023 11:30:50 -0400 Subject: [PATCH 084/320] Bump firebase-frameworks version in constants.ts (#6038) Fixes compatibility with latest Next.js --- src/frameworks/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frameworks/constants.ts b/src/frameworks/constants.ts index 63cc6cd18b0..5d4c8c24296 100644 --- a/src/frameworks/constants.ts +++ b/src/frameworks/constants.ts @@ -25,7 +25,7 @@ export const FEATURE_REQUEST_URL = "https://github.com/firebase/firebase-tools/issues/new?template=feature_request.md"; export const MAILING_LIST_URL = "https://goo.gle/41enW5X"; -export const FIREBASE_FRAMEWORKS_VERSION = "^0.10.1"; +export const FIREBASE_FRAMEWORKS_VERSION = "^0.10.4"; export const FIREBASE_FUNCTIONS_VERSION = "^4.3.0"; export const FIREBASE_ADMIN_VERSION = "^11.0.1"; export const SHARP_VERSION = "^0.32.1"; From 2b18e0bad4f234511054dbef2d8fa8407fccced4 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Mon, 26 Jun 2023 10:32:02 -0700 Subject: [PATCH 085/320] Revert emulators changes (#6030) --- firebase-vscode/src/cli.ts | 33 +---------------- firebase-vscode/src/extension.ts | 7 ---- firebase-vscode/src/workflow.ts | 47 ------------------------- firebase-vscode/webviews/SidebarApp.tsx | 2 -- 4 files changed, 1 insertion(+), 88 deletions(-) diff --git a/firebase-vscode/src/cli.ts b/firebase-vscode/src/cli.ts index 74d3a03f64b..beae5b8a777 100644 --- a/firebase-vscode/src/cli.ts +++ b/firebase-vscode/src/cli.ts @@ -14,17 +14,13 @@ import { requireAuth } from "../../src/requireAuth"; import { deploy } from "../../src/deploy"; import { getDefaultHostingSite } from "../../src/getDefaultHostingSite"; import { initAction } from "../../src/commands/init"; -import { startAll as startAllEmulators, cleanShutdown as stopAllEmulators } from "../../src/emulator/controller"; -import { EmulatorRegistry } from "../../src/emulator/registry"; -import { EmulatorInfo, Emulators } from "../../src/emulator/types"; import { Account, User } from "../../src/types/auth"; import { Options } from "../../src/options"; import { currentOptions, getCommandOptions } from "./options"; import { setInquirerOptions } from "./stubs/inquirer-stub"; import { ServiceAccount } from "../common/types"; import { listChannels } from "../../src/hosting/api"; -import * as commandUtils from "../../src/emulator/commandUtils"; -import { EmulatorUiSelections, ChannelWithId } from "../common/messaging/types"; +import { ChannelWithId } from "../common/messaging/types"; import { pluginLogger } from "./logger-wrapper"; import { Config } from "../../src/config"; @@ -170,33 +166,6 @@ export async function initHosting( setInquirerOptions(inquirerOptions); await initAction("hosting", commandOptions); } - -export async function emulatorsStart(emulatorUiSelections: EmulatorUiSelections) { - const commandOptions = await getCommandOptions(undefined, { - ...currentOptions, - project: emulatorUiSelections.projectId, - exportOnExit: emulatorUiSelections.exportStateOnExit, - import: emulatorUiSelections.importStateFolderPath, - only: emulatorUiSelections.mode === "hosting" ? "hosting" : "" - }); - // Adjusts some options, export on exit can be a boolean or a path. - commandUtils.setExportOnExitOptions(commandOptions as commandUtils.ExportOnExitOptions); - return startAllEmulators(commandOptions, /*showUi=*/ true); -} - -export async function stopEmulators() { - await stopAllEmulators(); -} - -export function listRunningEmulators(): EmulatorInfo[] { - return EmulatorRegistry.listRunningWithInfo(); -} - -export function getEmulatorUiUrl(): string | undefined { - const url: URL = EmulatorRegistry.url(Emulators.UI); - return url.hostname === "unknown" ? undefined : url.toString(); -} - export async function deployToHosting( firebaseJSON: Config, deployTarget: string diff --git a/firebase-vscode/src/extension.ts b/firebase-vscode/src/extension.ts index 368fecf5afb..7cc25c41d76 100644 --- a/firebase-vscode/src/extension.ts +++ b/firebase-vscode/src/extension.ts @@ -11,7 +11,6 @@ import { import { setupSidebar } from "./sidebar"; import { setupWorkflow } from "./workflow"; import { pluginLogger } from "./logger-wrapper"; -import { onShutdown } from "./workflow"; const broker = createBroker< ExtensionToWebviewParamsMap, @@ -26,9 +25,3 @@ export function activate(context: vscode.ExtensionContext) { setupWorkflow(context, broker); setupSidebar(context, broker); } - -// This method is called when the extension is deactivated -export async function deactivate() { - // This await is optimistic but it might wait for a moment longer while we run cleanup activities - await onShutdown(); -} diff --git a/firebase-vscode/src/workflow.ts b/firebase-vscode/src/workflow.ts index ce23f0b23d1..7ec6186cc6f 100644 --- a/firebase-vscode/src/workflow.ts +++ b/firebase-vscode/src/workflow.ts @@ -9,16 +9,12 @@ import { FirebaseProjectMetadata } from "../../src/types/project"; import { ExtensionBrokerImpl } from "./extension-broker"; import { deployToHosting, - emulatorsStart, getAccounts, getChannels, - getEmulatorUiUrl, initHosting, listProjects, - listRunningEmulators, login, logoutUser, - stopEmulators, } from "./cli"; import { User } from "../../src/types/auth"; import { currentOptions } from "./options"; @@ -364,47 +360,4 @@ export async function setupWorkflow( { projectId, folderPath: currentOptions.cwd }); await fetchChannels(true); } - broker.on( - "launchEmulators", - async ({ emulatorUiSelections }) => { - await emulatorsStart(emulatorUiSelections); - broker.send("notifyRunningEmulatorInfo", { uiUrl: getEmulatorUiUrl(), displayInfo: listRunningEmulators() }); - } - ); - - broker.on( - "stopEmulators", - async () => { - await stopEmulators(); - // Update the UI - broker.send("notifyEmulatorsStopped"); - } - ); - - broker.on( - "selectEmulatorImportFolder", - async () => { - const options: vscode.OpenDialogOptions = { - canSelectMany: false, - openLabel: `Pick an import folder`, - title: `Pick an import folder`, - canSelectFiles: false, - canSelectFolders: true, - }; - const fileUri = await vscode.window.showOpenDialog(options); - // Update the UI of the selection - if (!fileUri || fileUri.length < 1) { - vscode.window.showErrorMessage("Invalid import folder selected."); - return; - } - broker.send("notifyEmulatorImportFolder", { folder: fileUri[0].fsPath }); - } - ); -} - -/** - * Cleans up any open resources before shutting down. - */ -export async function onShutdown() { - await stopEmulators(); } diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx index c5f9e9bd77d..5a5b4c61175 100644 --- a/firebase-vscode/webviews/SidebarApp.tsx +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -9,7 +9,6 @@ import { ServiceAccountUser } from "../common/types"; import { DeployPanel } from "./components/DeployPanel"; import { HostingState } from "./webview-types"; import { ChannelWithId } from "./messaging/types"; -import { EmulatorPanel } from "./components/EmulatorPanel"; import { webLogger } from "./globals/web-logger"; import { InitFirebasePanel } from "./components/InitPanel"; @@ -146,7 +145,6 @@ export function SidebarApp() { }} /> )} - {(!!userEmail && !!firebaseJson) && } ); } From af7c645d63e17a2c4296020332f62003a3a1d086 Mon Sep 17 00:00:00 2001 From: Alex Astrum Date: Mon, 26 Jun 2023 15:24:26 -0400 Subject: [PATCH 086/320] Fix table in CONTRIBUTING.md (#6029) Multi-line table syntax is not supported in GitHub Markdown. --- CONTRIBUTING.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c8d2b16559..2617886a763 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -148,15 +148,10 @@ are unavailable to Pull Requests coming from forks of the repository. | path | description | | --------------- | --------------------------------------------------------- | | `src` | Contains shared/support code for the commands | -| `src/bin` | Contains the runnable script. You shouldn't need to touch | -: : this content. : -| `src/commands` | Contains code for the commands, organized by | -: : one-file-per-command with dashes. : -| `src/templates` | Contains static files needed for various reasons | -: : (inittemplates, login success HTML, etc.) : -| `src/test` | Contains tests. Mirrors the top-level directory structure | -: : (i.e., `src/test/commands` contains command tests and : -: : `src/test/gcp` contains `gcp` tests) : +| `src/bin` | Contains the runnable script. You shouldn't need to touch this content. | +| `src/commands` | Contains code for the commands, organized by one-file-per-command with dashes. | +| `src/templates` | Contains static files needed for various reasons (inittemplates, login success HTML, etc.) | +| `src/test` | Contains tests. Mirrors the top-level directory structure (i.e., `src/test/commands` contains command tests and `src/test/gcp` contains `gcp` tests) | ## Building CLI commands From 31c2d22df3cb89f8c08665371f628089e53bf9c8 Mon Sep 17 00:00:00 2001 From: blidd-google <112491344+blidd-google@users.noreply.github.com> Date: Tue, 27 Jun 2023 11:35:55 -0400 Subject: [PATCH 087/320] Implement module to link stack to GitHub repository (#5793) * add internal testing cmd for connecting gh to cloud build repos * use regex to extract repo slug * add comments * add unit tests * fix tests * refactoring & allow changing gh app access settings * refactor & update unit tests * add comments & change internaltesting name * rename to composer --- src/api.ts | 6 + src/commands/index.ts | 2 + .../internaltesting-frameworks-init.ts | 14 ++ src/gcp/cloudbuild.ts | 179 +++++++++++++++++ src/init/features/composer/repo.ts | 184 ++++++++++++++++++ src/test/init/features/composer.spec.ts | 134 +++++++++++++ src/utils.ts | 9 + 7 files changed, 528 insertions(+) create mode 100644 src/commands/internaltesting-frameworks-init.ts create mode 100644 src/gcp/cloudbuild.ts create mode 100644 src/init/features/composer/repo.ts create mode 100644 src/test/init/features/composer.spec.ts diff --git a/src/api.ts b/src/api.ts index 0a362e63758..86f827a2e35 100644 --- a/src/api.ts +++ b/src/api.ts @@ -94,6 +94,12 @@ export const functionsDefaultRegion = utils.envOverride( "FIREBASE_FUNCTIONS_DEFAULT_REGION", "us-central1" ); + +export const cloudbuildOrigin = utils.envOverride( + "FIREBASE_CLOUDBUILD_URL", + "https://cloudbuild.googleapis.com" +); + export const cloudschedulerOrigin = utils.envOverride( "FIREBASE_CLOUDSCHEDULER_URL", "https://cloudscheduler.googleapis.com" diff --git a/src/commands/index.ts b/src/commands/index.ts index 1b3c5d3bc30..b3fa211894e 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -150,6 +150,8 @@ export function load(client: any): any { client.internaltesting.frameworks.compose = loadCommand("internaltesting-frameworks-compose"); client.internaltesting.functions = {}; client.internaltesting.functions.discover = loadCommand("internaltesting-functions-discover"); + client.internaltesting.frameworks = {}; + client.internaltesting.frameworks.init = loadCommand("internaltesting-frameworks-init"); } client.login = loadCommand("login"); client.login.add = loadCommand("login-add"); diff --git a/src/commands/internaltesting-frameworks-init.ts b/src/commands/internaltesting-frameworks-init.ts new file mode 100644 index 00000000000..729fde0e9d9 --- /dev/null +++ b/src/commands/internaltesting-frameworks-init.ts @@ -0,0 +1,14 @@ +import { Command } from "../command"; +import { linkGitHubRepository } from "../init/features/composer/repo"; +import { Options } from "../options"; +import { needProjectId } from "../projectUtils"; +import requireInteractive from "../requireInteractive"; + +export const command = new Command("internaltesting:frameworks:init") + .description("connect github repo to cloud build") + .before(requireInteractive) + .action(async (options: Options) => { + const projectId = needProjectId(options); + await linkGitHubRepository(projectId, "us-central2", "stack0"); + // TODO: send repo metadata to control plane + }); diff --git a/src/gcp/cloudbuild.ts b/src/gcp/cloudbuild.ts new file mode 100644 index 00000000000..488d806ab94 --- /dev/null +++ b/src/gcp/cloudbuild.ts @@ -0,0 +1,179 @@ +import { Client } from "../apiv2"; +import { cloudbuildOrigin } from "../api"; + +const client = new Client({ + urlPrefix: cloudbuildOrigin, + auth: true, + apiVersion: "v2", +}); + +export interface OperationMetadata { + createTime: string; + endTime: string; + target: string; + verb: string; + requestedCancellation: boolean; + apiVersion: string; +} + +export interface Operation { + name: string; + metadata?: OperationMetadata; + done: boolean; + error?: { code: number; message: string; details: unknown }; + response?: any; +} + +export interface GitHubConfig { + authorizerCredential?: { + oauthTokenSecretVersion: string; + username: string; + }; + appInstallationId?: string; +} + +type InstallationStage = + | "STAGE_UNSPECIFIED" + | "PENDING_CREATE_APP" + | "PENDING_USER_OAUTH" + | "PENDING_INSTALL_APP" + | "COMPLETE"; + +type ConnectionOutputOnlyFields = "createTime" | "updateTime" | "installationState" | "reconciling"; + +export interface Connection { + name?: string; + disabled?: boolean; + annotations?: { + [key: string]: string; + }; + etag?: string; + githubConfig?: GitHubConfig; + createTime: string; + updateTime: string; + installationState: { + stage: InstallationStage; + message: string; + actionUri: string; + }; + reconciling: boolean; +} + +type RepositoryOutputOnlyFields = "createTime" | "updateTime"; + +export interface Repository { + name?: string; + remoteUri: string; + annotations?: { + [key: string]: string; + }; + etag?: string; + createTime: string; + updateTime: string; +} + +interface LinkableRepositories { + repositories: Repository[]; + nextPageToken: string; +} + +/** + * Creates a Cloud Build V2 Connection. + */ +export async function createConnection( + projectId: string, + location: string, + connectionId: string +): Promise { + const res = await client.post, Operation>( + `projects/${projectId}/locations/${location}/connections`, + { githubConfig: {} }, + { queryParams: { connectionId } } + ); + return res.body; +} + +/** + * Gets metadata for a Cloud Build V2 Connection. + */ +export async function getConnection( + projectId: string, + location: string, + connectionId: string +): Promise { + const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`; + const res = await client.get(name); + return res.body; +} + +/** + * Deletes a Cloud Build V2 Connection. + */ +export async function deleteConnection( + projectId: string, + location: string, + connectionId: string +): Promise { + const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`; + const res = await client.delete(name); + return res.body; +} + +/** + * Gets a list of repositories that can be added to the provided Connection. + */ +export async function fetchLinkableRepositories( + projectId: string, + location: string, + connectionId: string +): Promise { + const name = `projects/${projectId}/locations/${location}/connections/${connectionId}:fetchLinkableRepositories`; + const res = await client.get(name); + return res.body; +} + +/** + * Creates a Cloud Build V2 Repository. + */ +export async function createRepository( + projectId: string, + location: string, + connectionId: string, + repositoryId: string, + remoteUri: string +): Promise { + const res = await client.post, Operation>( + `projects/${projectId}/locations/${location}/connections/${connectionId}/repositories`, + { remoteUri }, + { queryParams: { repositoryId } } + ); + return res.body; +} + +/** + * Gets metadata for a Cloud Build V2 Repository. + */ +export async function getRepository( + projectId: string, + location: string, + connectionId: string, + repositoryId: string +): Promise { + const name = `projects/${projectId}/locations/${location}/connections/${connectionId}/repositories/${repositoryId}`; + const res = await client.get(name); + return res.body; +} + +/** + * Deletes a Cloud Build V2 Repository. + */ +export async function deleteRepository( + projectId: string, + location: string, + connectionId: string, + repositoryId: string +) { + const name = `projects/${projectId}/locations/${location}/connections/${connectionId}/repositories/${repositoryId}`; + const res = await client.delete(name); + return res.body; +} diff --git a/src/init/features/composer/repo.ts b/src/init/features/composer/repo.ts new file mode 100644 index 00000000000..c5080ffa73f --- /dev/null +++ b/src/init/features/composer/repo.ts @@ -0,0 +1,184 @@ +import { cloudbuildOrigin } from "../../../api"; +import { FirebaseError } from "../../../error"; +import * as gcb from "../../../gcp/cloudbuild"; +import { logger } from "../../../logger"; +import * as poller from "../../../operation-poller"; +import * as utils from "../../../utils"; +import { promptOnce } from "../../../prompt"; + +const gcbPollerOptions: Omit = { + apiOrigin: cloudbuildOrigin, + apiVersion: "v2", + masterTimeout: 25 * 60 * 1_000, + maxBackoff: 10_000, +}; + +/** + * Example usage: + * extractRepoSlugFromURI("https://github.com/user/repo.git") => "user/repo" + */ +function extractRepoSlugFromURI(remoteUri: string): string | undefined { + const match = /github.com\/(.+).git/.exec(remoteUri); + if (!match) { + return undefined; + } + return match[1]; +} + +function generateConnectionId(stackId: string): string { + return `composer-${stackId}-conn`; +} + +/** + * Generates a repository ID. + * N.B. The deterministic nature of the repository ID implies that each + * Cloud Build Connection will have one Cloud Build Repo child resource. + * The current implementation is subject to change in the event that + * the 1:1 Connection-to-Resource relationship no longer holds. + */ +function generateRepositoryId(): string | undefined { + return `composer-repo`; +} + +/** + * Prompts the user to link their stack to a GitHub repository. + */ +export async function linkGitHubRepository( + projectId: string, + location: string, + stackId: string +): Promise { + const connectionId = generateConnectionId(stackId); + await getOrCreateConnection(projectId, location, connectionId); + + let remoteUri = await promptRepositoryURI(projectId, location, connectionId); + while (remoteUri === "") { + await utils.openInBrowser("https://github.com/apps/google-cloud-build/installations/new"); + await promptOnce({ + type: "input", + message: + "Press any key once you have finished configuring your installation's access settings.", + }); + remoteUri = await promptRepositoryURI(projectId, location, connectionId); + } + + const repo = await getOrCreateRepository(projectId, location, connectionId, remoteUri); + logger.info(`Successfully linked GitHub repository at remote URI ${remoteUri}.`); + return repo; +} + +async function promptRepositoryURI( + projectId: string, + location: string, + connectionId: string +): Promise { + const resp = await gcb.fetchLinkableRepositories(projectId, location, connectionId); + if (!resp.repositories || resp.repositories.length === 0) { + throw new FirebaseError( + "The GitHub App does not have access to any repositories. Please configure " + + "your app installation permissions at https://github.com/settings/installations." + ); + } + const choices = resp.repositories.map((repo: gcb.Repository) => ({ + name: extractRepoSlugFromURI(repo.remoteUri) || repo.remoteUri, + value: repo.remoteUri, + })); + choices.push({ + name: "Missing a repo? Select this option to configure your installation's access settings", + value: "", + }); + + return await promptOnce({ + type: "list", + message: "Which of the following repositories would you like to link?", + choices, + }); +} + +async function promptConnectionAuth( + conn: gcb.Connection, + projectId: string, + location: string, + connectionId: string +): Promise { + logger.info(conn.installationState.message); + logger.info(conn.installationState.actionUri); + await utils.openInBrowser(conn.installationState.actionUri); + await promptOnce({ + type: "input", + message: + "Press any key once you have authorized the app (Cloud Build) to access your GitHub repo.", + }); + return await gcb.getConnection(projectId, location, connectionId); +} + +/** + * Exported for unit testing. + */ +export async function getOrCreateConnection( + projectId: string, + location: string, + connectionId: string +): Promise { + let conn: gcb.Connection; + try { + conn = await gcb.getConnection(projectId, location, connectionId); + } catch (err: unknown) { + if ((err as FirebaseError).status === 404) { + const op = await gcb.createConnection(projectId, location, connectionId); + conn = await poller.pollOperation({ + ...gcbPollerOptions, + pollerName: `create-${location}-${connectionId}`, + operationResourceName: op.name, + }); + } else { + throw err; + } + } + + while (conn.installationState.stage !== "COMPLETE") { + conn = await promptConnectionAuth(conn, projectId, location, connectionId); + } + return conn; +} + +/** + * Exported for unit testing. + */ +export async function getOrCreateRepository( + projectId: string, + location: string, + connectionId: string, + remoteUri: string +): Promise { + const repositoryId = generateRepositoryId(); + if (!repositoryId) { + throw new FirebaseError(`Failed to generate repositoryId for URI "${remoteUri}".`); + } + let repo: gcb.Repository; + try { + repo = await gcb.getRepository(projectId, location, connectionId, repositoryId); + const repoSlug = extractRepoSlugFromURI(repo.remoteUri); + if (repoSlug) { + throw new FirebaseError(`${repoSlug} has already been linked.`); + } + } catch (err: unknown) { + if ((err as FirebaseError).status === 404) { + const op = await gcb.createRepository( + projectId, + location, + connectionId, + repositoryId, + remoteUri + ); + repo = await poller.pollOperation({ + ...gcbPollerOptions, + pollerName: `create-${location}-${connectionId}-${repositoryId}`, + operationResourceName: op.name, + }); + } else { + throw err; + } + } + return repo; +} diff --git a/src/test/init/features/composer.spec.ts b/src/test/init/features/composer.spec.ts new file mode 100644 index 00000000000..661bdd831aa --- /dev/null +++ b/src/test/init/features/composer.spec.ts @@ -0,0 +1,134 @@ +import * as sinon from "sinon"; +import { expect } from "chai"; + +import * as gcb from "../../../gcp/cloudbuild"; +import * as prompt from "../../../prompt"; +import * as poller from "../../../operation-poller"; +import { FirebaseError } from "../../../error"; +import * as repo from "../../../init/features/composer/repo"; +import * as utils from "../../../utils"; + +describe("composer", () => { + const sandbox: sinon.SinonSandbox = sinon.createSandbox(); + + let promptOnceStub: sinon.SinonStub; + let pollOperationStub: sinon.SinonStub; + let getConnectionStub: sinon.SinonStub; + let getRepositoryStub: sinon.SinonStub; + let createConnectionStub: sinon.SinonStub; + let createRepositoryStub: sinon.SinonStub; + let fetchLinkableRepositoriesStub: sinon.SinonStub; + + beforeEach(() => { + promptOnceStub = sandbox.stub(prompt, "promptOnce").throws("Unexpected promptOnce call"); + pollOperationStub = sandbox + .stub(poller, "pollOperation") + .throws("Unexpected pollOperation call"); + getConnectionStub = sandbox.stub(gcb, "getConnection").throws("Unexpected getConnection call"); + getRepositoryStub = sandbox.stub(gcb, "getRepository").throws("Unexpected getRepository call"); + createConnectionStub = sandbox + .stub(gcb, "createConnection") + .throws("Unexpected createConnection call"); + createRepositoryStub = sandbox + .stub(gcb, "createRepository") + .throws("Unexpected createRepository call"); + fetchLinkableRepositoriesStub = sandbox + .stub(gcb, "fetchLinkableRepositories") + .throws("Unexpected fetchLinkableRepositories call"); + + sandbox.stub(utils, "openInBrowser").resolves(); + }); + + afterEach(() => { + sandbox.verifyAndRestore(); + }); + + describe("connect GitHub repo", () => { + const projectId = "projectId"; + const location = "us-central1"; + const stackId = "stack0"; + const connectionId = `composer-${stackId}-conn`; + + const op = { + name: `projects/${projectId}/locations/${location}/connections/${connectionId}`, + done: true, + }; + const pendingConn = { + name: `projects/${projectId}/locations/${location}/connections/${connectionId}`, + disabled: false, + createTime: "0", + updateTime: "1", + installationState: { + stage: "PENDING_USER_OAUTH", + message: "pending", + actionUri: "https://google.com", + }, + reconciling: false, + }; + const completeConn = { + name: `projects/${projectId}/locations/${location}/connections/${connectionId}`, + disabled: false, + createTime: "0", + updateTime: "1", + installationState: { + stage: "COMPLETE", + message: "complete", + actionUri: "https://google.com", + }, + reconciling: false, + }; + const repos = { + repositories: [ + { + name: "repo0", + remoteUri: "https://github.com/test/repo0.git", + }, + { + name: "repo1", + remoteUri: "https://github.com/test/repo1.git", + }, + ], + }; + + it("creates a connection if it doesn't exist", async () => { + getConnectionStub.onFirstCall().rejects(new FirebaseError("error", { status: 404 })); + getConnectionStub.onSecondCall().resolves(completeConn); + createConnectionStub.resolves(op); + pollOperationStub.resolves(pendingConn); + promptOnceStub.onFirstCall().resolves("any key"); + + await repo.getOrCreateConnection(projectId, location, connectionId); + expect(createConnectionStub).to.be.calledWith(projectId, location, connectionId); + }); + + it("creates repository if it doesn't exist", async () => { + getConnectionStub.resolves(completeConn); + fetchLinkableRepositoriesStub.resolves(repos); + promptOnceStub.onFirstCall().resolves(repos.repositories[0].remoteUri); + getRepositoryStub.rejects(new FirebaseError("error", { status: 404 })); + createRepositoryStub.resolves({ name: "op" }); + pollOperationStub.resolves(repos.repositories[0]); + + await repo.getOrCreateRepository( + projectId, + location, + connectionId, + repos.repositories[0].remoteUri + ); + expect(createRepositoryStub).to.be.calledWith( + projectId, + location, + connectionId, + "composer-repo", + repos.repositories[0].remoteUri + ); + }); + + it("throws error if no linkable repositories are available", async () => { + getConnectionStub.resolves(pendingConn); + fetchLinkableRepositoriesStub.resolves({ repositories: [] }); + + await expect(repo.linkGitHubRepository(projectId, location, stackId)).to.be.rejected; + }); + }); +}); diff --git a/src/utils.ts b/src/utils.ts index 39c517587b2..318c58d530c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,6 +2,7 @@ import * as _ from "lodash"; import * as url from "url"; import * as http from "http"; import * as clc from "colorette"; +import * as open from "open"; import * as ora from "ora"; import * as process from "process"; import { Readable } from "stream"; @@ -764,3 +765,11 @@ export function connectableHostname(hostname: string): string { } return hostname; } + +/** + * We wrap and export the open() function from the "open" package + * to stub it out in unit tests. + */ +export async function openInBrowser(url: string): Promise { + await open(url); +} From e96b069feb2b0f66a6007c22efe7056b4967b1cb Mon Sep 17 00:00:00 2001 From: joehan Date: Tue, 27 Jun 2023 12:42:02 -0700 Subject: [PATCH 088/320] Imporved extensions metrics (#6037) * Switched most uses of track to GA4 * Move duration out of params, and improve debug logging slightly * Improved metrics for extensions * formats --- src/deploy/extensions/args.ts | 1 + src/deploy/extensions/deploy.ts | 1 - src/deploy/extensions/prepare.ts | 1 + src/deploy/extensions/release.ts | 15 +++++++++++++++ src/deploy/hosting/deploy.ts | 6 ------ src/emulator/controller.ts | 6 +++++- src/track.ts | 4 +++- 7 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/deploy/extensions/args.ts b/src/deploy/extensions/args.ts index 2ff5221e1cf..d7398c4bf56 100644 --- a/src/deploy/extensions/args.ts +++ b/src/deploy/extensions/args.ts @@ -10,4 +10,5 @@ export interface Payload { export interface Context { have?: planner.DeploymentInstanceSpec[]; want?: planner.DeploymentInstanceSpec[]; + extensionsStartTime?: number; } diff --git a/src/deploy/extensions/deploy.ts b/src/deploy/extensions/deploy.ts index 47e1edcbf53..e49d7462f17 100644 --- a/src/deploy/extensions/deploy.ts +++ b/src/deploy/extensions/deploy.ts @@ -59,7 +59,6 @@ export async function deploy(context: Context, options: Options, payload: Payloa validationQueue.process(); validationQueue.close(); - await validationPromise; if (errorHandler.hasErrors()) { diff --git a/src/deploy/extensions/prepare.ts b/src/deploy/extensions/prepare.ts index 403af32073d..47a3b3820ad 100644 --- a/src/deploy/extensions/prepare.ts +++ b/src/deploy/extensions/prepare.ts @@ -17,6 +17,7 @@ import { checkSpecForV2Functions, ensureNecessaryV2ApisAndRoles } from "./v2Func import { acceptLatestAppDeveloperTOS } from "../../extensions/tos"; export async function prepare(context: Context, options: Options, payload: Payload) { + context.extensionsStartTime = Date.now(); const projectId = needProjectId(options); const projectNumber = await needProjectNumber(options); const aliases = getAliases(options, projectId); diff --git a/src/deploy/extensions/release.ts b/src/deploy/extensions/release.ts index a8501a02242..67a5063b0f2 100644 --- a/src/deploy/extensions/release.ts +++ b/src/deploy/extensions/release.ts @@ -7,6 +7,7 @@ import { ErrorHandler } from "./errors"; import { Options } from "../../options"; import { needProjectId } from "../../projectUtils"; import { saveEtags } from "../../extensions/etags"; +import { trackGA4 } from "../../track"; export async function release(context: Context, options: Options, payload: Payload) { const projectId = needProjectId(options); @@ -45,6 +46,20 @@ export async function release(context: Context, options: Options, payload: Paylo deploymentQueue.close(); await deploymentPromise; + // extensionsStartTime should always be populated, but if not, fall back to something that won't break us. + const duration = context.extensionsStartTime ? Date.now() - context.extensionsStartTime : 1; + await trackGA4( + "extensions_deploy", + { + extension_instance_created: payload.instancesToCreate?.length ?? 0, + extension_instance_updated: payload.instancesToUpdate?.length ?? 0, + extension_instance_configured: payload.instancesToConfigure?.length ?? 0, + extension_instance_deleted: payload.instancesToDelete?.length ?? 0, + errors: errorHandler.errors.length ?? 0, + interactive: options.nonInteractive ? "false" : "true", + }, + duration + ); // After deployment, write the latest etags to RC so we can detect out of band changes in the next deploy. const newHave = await planner.have(projectId); diff --git a/src/deploy/hosting/deploy.ts b/src/deploy/hosting/deploy.ts index 2f9fc4e528a..279b250cef7 100644 --- a/src/deploy/hosting/deploy.ts +++ b/src/deploy/hosting/deploy.ts @@ -2,7 +2,6 @@ import { Uploader } from "./uploader"; import { detectProjectRoot } from "../../detectProjectRoot"; import { listFiles } from "../../listFiles"; import { logger } from "../../logger"; -import { track } from "../../track"; import { envOverride, logLabeledBullet, logLabeledSuccess } from "../../utils"; import { bold, cyan } from "colorette"; import * as ora from "ora"; @@ -88,9 +87,6 @@ export async function deploy(context: Context, options: Options): Promise try { await uploader.start(); - } catch (err: any) { - void track("Hosting Deploy", "failure"); - throw err; } finally { clearInterval(progressInterval); updateSpinner(uploader.statusMessage(), debugging); @@ -103,8 +99,6 @@ export async function deploy(context: Context, options: Options): Promise logLabeledSuccess(`hosting[${deploy.config.site}]`, "file upload complete"); const dt = Date.now() - t0; logger.debug(`[hosting] deploy completed after ${dt}ms`); - - void track("Hosting Deploy", "success", dt); return runDeploys(deploys, debugging); } diff --git a/src/emulator/controller.ts b/src/emulator/controller.ts index 7505bf9ea81..1950cb0b346 100644 --- a/src/emulator/controller.ts +++ b/src/emulator/controller.ts @@ -4,7 +4,7 @@ import * as path from "path"; import * as fsConfig from "../firestore/fsConfig"; import { logger } from "../logger"; -import { trackEmulator } from "../track"; +import { trackEmulator, trackGA4 } from "../track"; import * as utils from "../utils"; import { EmulatorRegistry } from "./registry"; import { @@ -351,6 +351,10 @@ export async function startAll( extensionsBackends ); emulatableBackends.push(...filteredExtensionsBackends); + trackGA4("extensions_emulated", { + number_of_extensions_emulated: filteredExtensionsBackends.length, + number_of_extensions_ignored: extensionsBackends.length - filteredExtensionsBackends.length, + }); } const listenConfig = {} as Record; diff --git a/src/track.ts b/src/track.ts index c1aa68eaf33..69a0c92f4bd 100644 --- a/src/track.ts +++ b/src/track.ts @@ -14,7 +14,9 @@ type cliEventNames = | "login" | "api_enabled" | "hosting_version" - | "extension_added_to_manifest"; + | "extension_added_to_manifest" + | "extensions_deploy" + | "extensions_emulated"; type GA4Property = "cli" | "emulator"; interface GA4Info { measurementId: string; From 3ca530ca85fa2e4deb56d617b034b9423b6900a6 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 27 Jun 2023 21:32:18 +0000 Subject: [PATCH 089/320] 12.4.1 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 018218f8e08..6a9fdbca629 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.4.0", + "version": "12.4.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.4.0", + "version": "12.4.1", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index a93b3c2d71d..c9334a89044 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.4.0", + "version": "12.4.1", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From a21ac90519b960b3c4f6465546dd02a3b7a3a1e6 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Tue, 27 Jun 2023 21:32:33 +0000 Subject: [PATCH 090/320] [firebase-release] Removed change log and reset repo after 12.4.1 release --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65ff9f56488..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +0,0 @@ -- Release Firestore emulator 1.18.1 which addes a emulator configuration to start with experimental mode (#5942). -- Run lifecycle hooks for specific codebases. (#6011) -- Fixed issue causing `firebase emulators:start` to crash in Next.js apps (#6005) From 2e8e909ca438f230854e8cbb8091fb40026218cf Mon Sep 17 00:00:00 2001 From: Alex Pascal Date: Tue, 27 Jun 2023 15:08:05 -0700 Subject: [PATCH 091/320] Refactored ext:install to use the latest extension metadata. (#5997) * Added cascading of latest approved version to latest version when installing. * Changed output of extension version info. * Formatting, added more metadata, and cleaned up TODOs. * Formatting and extra notices. * Added even more metadata. * Formatting. * Fixing tests. * Added display of extension resources. * Added link to Extensions Hub. * Added displaying of events. * Formatting. * Formatting. * Version bug. * Added displaying of secrets and task queues. * Added displaying of external services. * Fixed resolveVersion() + tests. * Added tests for displayExtensionInfo(). * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: joehan * Better messaging and parameterizing. * Update displayExtensionInfo.ts * Update displayExtensionInfo.spec.ts * Update CHANGELOG.md --------- Co-authored-by: joehan --- CHANGELOG.md | 1 + src/commands/ext-configure.ts | 2 - src/commands/ext-install.ts | 143 ++++++------- src/commands/ext-update.ts | 2 - src/deploy/extensions/planner.ts | 25 +-- src/extensions/displayExtensionInfo.ts | 197 ++++++++++++------ src/extensions/extensionsHelper.ts | 23 -- src/extensions/paramHelper.ts | 2 - src/extensions/types.ts | 6 + src/extensions/updateHelper.ts | 6 +- src/test/deploy/extensions/planner.spec.ts | 31 +-- .../extensions/displayExtensionInfo.spec.ts | 184 ++++++++-------- src/test/extensions/extensionsHelper.spec.ts | 35 ---- 13 files changed, 327 insertions(+), 330 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..2668eb75f0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Refactored `ext:install` to use the latest extension metadata. (#5997) diff --git a/src/commands/ext-configure.ts b/src/commands/ext-configure.ts index 994523de058..fd6ba7e6577 100644 --- a/src/commands/ext-configure.ts +++ b/src/commands/ext-configure.ts @@ -88,8 +88,6 @@ export const command = new Command("ext:configure ") projectId, paramSpecs: tbdParams, nonInteractive: false, - // TODO(b/230598656): Clean up paramsEnvPath after v11 launch. - paramsEnvPath: "", instanceId, reconfiguring: true, }); diff --git a/src/commands/ext-install.ts b/src/commands/ext-install.ts index 35e55d2d09c..4e722975a17 100644 --- a/src/commands/ext-install.ts +++ b/src/commands/ext-install.ts @@ -1,12 +1,14 @@ import * as clc from "colorette"; import { marked } from "marked"; +import * as semver from "semver"; import * as TerminalRenderer from "marked-terminal"; -import { displayExtInfo } from "../extensions/displayExtensionInfo"; +import { displayExtensionVersionInfo } from "../extensions/displayExtensionInfo"; import * as askUserForEventsConfig from "../extensions/askUserForEventsConfig"; import { checkMinRequiredVersion } from "../checkMinRequiredVersion"; import { Command } from "../command"; import { FirebaseError } from "../error"; +import { logger } from "../logger"; import { getProjectId, needProjectId } from "../projectUtils"; import * as extensionsApi from "../extensions/extensionsApi"; import { ExtensionVersion, ExtensionSource } from "../extensions/types"; @@ -17,13 +19,11 @@ import { createSourceFromLocation, ensureExtensionsApiEnabled, logPrefix, - promptForOfficialExtension, promptForValidInstanceId, diagnoseAndFixProject, - isUrlPath, isLocalPath, - canonicalizeRefInput, } from "../extensions/extensionsHelper"; +import { resolveVersion } from "../deploy/extensions/planner"; import { getRandomString } from "../extensions/utils"; import { requirePermissions } from "../requirePermissions"; import * as utils from "../utils"; @@ -40,7 +40,7 @@ marked.setOptions({ /** * Command for installing an extension */ -export const command = new Command("ext:install [extensionName]") +export const command = new Command("ext:install [extensionRef]") .description( "add an uploaded extension to firebase.json if [publisherId/extensionId] is provided;" + "or, add a local extension if [localPath] is provided" @@ -51,67 +51,80 @@ export const command = new Command("ext:install [extensionName]") .before(ensureExtensionsApiEnabled) .before(checkMinRequiredVersion, "extMinVersion") .before(diagnoseAndFixProject) - .action(async (extensionName: string, options: Options) => { - const projectId = getProjectId(options); - // TODO(b/230598656): Clean up paramsEnvPath after v11 launch. - const paramsEnvPath = ""; - let learnMore = false; - if (!extensionName) { - if (options.interactive) { - learnMore = true; - extensionName = await promptForOfficialExtension( - "Which official extension do you wish to install?\n" + - " Select an extension, then press Enter to learn more." - ); - } else { - throw new FirebaseError( - `Unable to find published extension '${clc.bold(extensionName)}'. ` + - `Run ${clc.bold( - "firebase ext:install -i" - )} to select from the list of all available published extensions.` - ); - } - } - let source; - let extensionVersion; - - // TODO(b/220900194): Remove when deprecating old install flow. - // --local doesn't support urlPath so this will become dead codepath. - if (isUrlPath(extensionName)) { - throw new FirebaseError( - `Installing with a source url is no longer supported in the CLI. Please use Firebase Console instead.` - ); - } + .action(async (extensionRef: string, options: Options) => { if (options.local) { utils.logLabeledWarning( logPrefix, "As of firebase-tools@11.0.0, the `--local` flag is no longer required, as it is the default behavior." ); } - + if (!extensionRef) { + throw new FirebaseError( + "Extension ref is required to install. To see a full list of available extensions, go to Extensions Hub (https://extensions.dev/extensions)." + ); + } + let source: ExtensionSource | undefined; + let extensionVersion: ExtensionVersion | undefined; + const projectId = getProjectId(options); // If the user types in a local path (prefixed with ~/, ../, or ./), install from local source. // Otherwise, treat the input as an extension reference and proceed with reference-based installation. - if (isLocalPath(extensionName)) { + if (isLocalPath(extensionRef)) { // TODO(b/228444119): Create source should happen at deploy time. // Should parse spec locally so we don't need project ID. - source = await createSourceFromLocation(needProjectId({ projectId }), extensionName); - await displayExtInfo(extensionName, "", source.spec); + source = await createSourceFromLocation(needProjectId({ projectId }), extensionRef); + await displayExtensionVersionInfo({ spec: source.spec }); void trackGA4("extension_added_to_manifest", { published: "local", interactive: options.nonInteractive ? "false" : "true", }); } else { - extensionName = await canonicalizeRefInput(extensionName); - extensionVersion = await extensionsApi.getExtensionVersion(extensionName); - + const extension = await extensionsApi.getExtension(extensionRef); + const ref = refs.parse(extensionRef); + ref.version = await resolveVersion(ref, extension); + const extensionVersionRef = refs.toExtensionVersionRef(ref); + extensionVersion = await extensionsApi.getExtensionVersion(extensionVersionRef); void trackGA4("extension_added_to_manifest", { published: extensionVersion.listing?.state === "APPROVED" ? "published" : "uploaded", interactive: options.nonInteractive ? "false" : "true", }); - await infoExtensionVersion({ - extensionName, + await displayExtensionVersionInfo({ + spec: extensionVersion.spec, extensionVersion, + latestApprovedVersion: extension.latestApprovedVersion, + latestVersion: extension.latestVersion, }); + if (extensionVersion.state === "DEPRECATED") { + throw new FirebaseError( + `Extension version ${clc.bold( + extensionVersionRef + )} is deprecated and cannot be installed. To install the latest non-deprecated version, omit the version in the extension ref.` + ); + } + logger.info(); + // Check if selected version is older than the latest approved version, or the latest version only if there is no approved version. + if ( + (extension.latestApprovedVersion && + semver.gt(extension.latestApprovedVersion, extensionVersion.spec.version)) || + (!extension.latestApprovedVersion && + extension.latestVersion && + semver.gt(extension.latestVersion, extensionVersion.spec.version)) + ) { + const version = extension.latestApprovedVersion || extension.latestVersion; + logger.info( + `You are about to install extension version ${clc.bold( + extensionVersion.spec.version + )} which is older than the latest ${ + extension.latestApprovedVersion ? "accepted version" : "version" + } ${clc.bold(version!)}.` + ); + } + } + if (!source && !extensionVersion) { + throw new FirebaseError( + `Failed to parse ${clc.bold( + extensionRef + )} as an extension version or a path to a local extension. Please specify a valid reference.` + ); } if ( !(await confirm({ @@ -122,33 +135,18 @@ export const command = new Command("ext:install [extensionName]") ) { return; } - if (!source && !extensionVersion) { - throw new FirebaseError( - "Could not find a source. Please specify a valid source to continue." - ); - } const spec = source?.spec ?? extensionVersion?.spec; if (!spec) { throw new FirebaseError( `Could not find the extension.yaml for extension '${clc.bold( - extensionName + extensionRef )}'. Please make sure this is a valid extension and try again.` ); } - if (learnMore) { - utils.logLabeledBullet( - logPrefix, - `You selected: ${clc.bold(spec.displayName || "")}.\n` + - `${spec.description}\n` + - `View details: https://firebase.google.com/products/extensions/${spec.name}\n` - ); - } - try { return installToManifest({ - paramsEnvPath, projectId, - extensionName, + extensionRef, source, extVersion: extensionVersion, nonInteractive: options.nonInteractive, @@ -164,18 +162,9 @@ export const command = new Command("ext:install [extensionName]") } }); -async function infoExtensionVersion(args: { - extensionName: string; - extensionVersion: ExtensionVersion; -}): Promise { - const ref = refs.parse(args.extensionName); - await displayExtInfo(args.extensionName, ref.publisherId, args.extensionVersion.spec, true); -} - interface InstallExtensionOptions { - paramsEnvPath?: string; projectId?: string; - extensionName: string; + extensionRef: string; source?: ExtensionSource; extVersion?: ExtensionVersion; nonInteractive: boolean; @@ -189,14 +178,13 @@ interface InstallExtensionOptions { * @param options */ async function installToManifest(options: InstallExtensionOptions): Promise { - const { projectId, extensionName, extVersion, source, paramsEnvPath, nonInteractive, force } = - options; - const isLocalSource = isLocalPath(extensionName); + const { projectId, extensionRef, extVersion, source, nonInteractive, force } = options; + const isLocalSource = isLocalPath(extensionRef); const spec = extVersion?.spec ?? source?.spec; if (!spec) { throw new FirebaseError( - `Could not find the extension.yaml for ${extensionName}. Please make sure this is a valid extension and try again.` + `Could not find the extension.yaml for ${extensionRef}. Please make sure this is a valid extension and try again.` ); } @@ -215,7 +203,6 @@ async function installToManifest(options: InstallExtensionOptions): Promise [updateSour newSpec: newExtensionVersion.spec, currentParams: oldParamValues, projectId, - // TODO(b/230598656): Clean up paramsEnvPath after v11 launch. - paramsEnvPath: "", nonInteractive: options.nonInteractive, instanceId, }); diff --git a/src/deploy/extensions/planner.ts b/src/deploy/extensions/planner.ts index 8a389e3e3dc..75c1778f2e9 100644 --- a/src/deploy/extensions/planner.ts +++ b/src/deploy/extensions/planner.ts @@ -207,32 +207,33 @@ export async function want(args: { } /** - * resolveVersion resolves a semver string to the max matching version. - * Exported for testing. - * @param publisherId - * @param extensionId - * @param version a semver or semver range + * Resolves a semver string to the max matching version. If no version is specified, + * it will default to the extension's latest approved version if set, otherwise to the latest version. + * + * @param ref the extension version ref + * @param extension the extension (optional) */ -export async function resolveVersion(ref: refs.Ref): Promise { +export async function resolveVersion(ref: refs.Ref, extension?: Extension): Promise { const extensionRef = refs.toExtensionRef(ref); - const extension = await extensionsApi.getExtension(extensionRef); - if (!ref.version || ref.version === "latest-approved") { - if (!extension.latestApprovedVersion) { + if (!ref.version && extension?.latestApprovedVersion) { + return extension.latestApprovedVersion; + } + if (ref.version === "latest-approved") { + if (!extension?.latestApprovedVersion) { throw new FirebaseError( `${extensionRef} has not been published to Extensions Hub (https://extensions.dev). To install it, you must specify the version you want to install.` ); } return extension.latestApprovedVersion; } - if (ref.version === "latest") { - if (!extension.latestVersion) { + if (!ref.version || ref.version === "latest") { + if (!extension?.latestVersion) { throw new FirebaseError( `${extensionRef} has no stable non-deprecated versions. If you wish to install a prerelease version, you must specify the version you want to install.` ); } return extension.latestVersion; } - const versions = await extensionsApi.listExtensionVersions(extensionRef, undefined, true); if (versions.length === 0) { throw new FirebaseError(`No versions found for ${extensionRef}`); diff --git a/src/extensions/displayExtensionInfo.ts b/src/extensions/displayExtensionInfo.ts index aef30fe192a..fc23c344f7b 100644 --- a/src/extensions/displayExtensionInfo.ts +++ b/src/extensions/displayExtensionInfo.ts @@ -1,12 +1,23 @@ import * as clc from "colorette"; import { marked } from "marked"; +import * as semver from "semver"; import * as TerminalRenderer from "marked-terminal"; +import * as path from "path"; -import * as utils from "../utils"; -import { logPrefix } from "./extensionsHelper"; +import * as refs from "../extensions/refs"; import { logger } from "../logger"; -import { FirebaseError } from "../error"; -import { Api, ExtensionSpec, Role, Resource, FUNCTIONS_RESOURCE_TYPE } from "./types"; +import { + Api, + ExtensionSpec, + ExtensionVersion, + LifecycleEvent, + ExternalService, + Role, + Param, + Resource, + FUNCTIONS_RESOURCE_TYPE, + EventDescriptor, +} from "./types"; import * as iam from "../gcp/iam"; import { SECRET_ROLE, usesSecrets } from "./secretsUtils"; @@ -18,33 +29,77 @@ const TASKS_ROLE = "cloudtasks.enqueuer"; const TASKS_API = "cloudtasks.googleapis.com"; /** - * displayExtInfo prints the extension info displayed when running ext:install. + * Displays info about an extension version, whether it is uploaded to the registry or a local spec. * - * @param extensionName name of the extension to display information about - * @param spec extension spec - * @param published whether or not the extension is a published extension - */ -export async function displayExtInfo( - extensionName: string, - publisher: string, - spec: ExtensionSpec, - published = false -): Promise { - const lines = []; - lines.push(`**Name**: ${spec.displayName}`); - if (publisher) { - lines.push(`**Publisher**: ${publisher}`); - } + * @param spec the extension spec + * @param extensionVersion the extension version + * */ +export async function displayExtensionVersionInfo(args: { + spec: ExtensionSpec; + extensionVersion?: ExtensionVersion; + latestApprovedVersion?: string; + latestVersion?: string; +}): Promise { + const { spec, extensionVersion, latestApprovedVersion, latestVersion } = args; + const lines: string[] = []; + const extensionRef = extensionVersion + ? refs.toExtensionRef(refs.parse(extensionVersion?.ref)) + : ""; + lines.push( + `${clc.bold("Extension:")} ${spec.displayName ?? "Unnamed extension"} ${ + extensionRef ? `(${extensionRef})` : "" + }` + ); if (spec.description) { - lines.push(`**Description**: ${spec.description}`); + lines.push(`${clc.bold("Description:")} ${spec.description}`); + } + let versionNote = ""; + const latestRelevantVersion = latestApprovedVersion || latestVersion; + if (latestRelevantVersion && semver.eq(spec.version, latestRelevantVersion)) { + versionNote = `- ${clc.green("Latest")}`; + } + if (extensionVersion?.state === "DEPRECATED") { + versionNote = `- ${clc.red("Deprecated")}`; } - if (published) { - if (spec.license) { - lines.push(`**License**: ${spec.license}`); + lines.push(`${clc.bold("Version:")} ${spec.version} ${versionNote}`); + if (extensionVersion) { + let reviewStatus: string; + switch (extensionVersion.listing?.state) { + case "APPROVED": + reviewStatus = clc.bold(clc.green("Accepted")); + break; + case "REJECTED": + reviewStatus = clc.bold(clc.red("Rejected")); + break; + default: + reviewStatus = clc.bold(clc.yellow("Unreviewed")); } - if (spec.sourceUrl) { - lines.push(`**Source code**: ${spec.sourceUrl}`); + lines.push(`${clc.bold("Review status:")} ${reviewStatus}`); + if (latestApprovedVersion) { + lines.push( + `${clc.bold("View in Extensions Hub:")} https://extensions.dev/extensions/${extensionRef}` + ); } + if (extensionVersion.buildSourceUri) { + const buildSourceUri = new URL(extensionVersion.buildSourceUri!); + buildSourceUri.pathname = path.join( + buildSourceUri.pathname, + extensionVersion.extensionRoot ?? "" + ); + lines.push(`${clc.bold("Source in GitHub:")} ${buildSourceUri}`); + } else { + lines.push( + `${clc.bold("Source download URI:")} ${extensionVersion.sourceDownloadUri ?? "-"}` + ); + } + } + lines.push(`${clc.bold("License:")} ${spec.license ?? "-"}`); + lines.push(displayResources(spec)); + if (spec.events?.length) { + lines.push(displayEvents(spec)); + } + if (spec.externalServices?.length) { + lines.push(displayExternalServices(spec)); } const apis = impliedApis(spec); if (apis.length) { @@ -54,33 +109,59 @@ export async function displayExtInfo( if (roles.length) { lines.push(await displayRoles(roles)); } - if (lines.length > 0) { - utils.logLabeledBullet(logPrefix, `information about '${clc.bold(extensionName)}':`); - const infoStr = lines.join("\n"); - // Convert to markdown and convert any trailing newlines to a single newline. - const formatted = marked(infoStr).replace(/\n+$/, "\n"); - logger.info(formatted); - // Return for testing purposes. - return lines; - } else { - throw new FirebaseError( - "Error occurred during installation: cannot parse info from source spec", - { - context: { - spec: spec, - extensionName: extensionName, - }, - } - ); - } + logger.info(`\n${lines.join("\n")}`); + return lines; } -/** - * Prints a clickable link where users can download the source code for an Extension Version. - */ -export function printSourceDownloadLink(sourceDownloadUri: string): void { - const sourceDownloadMsg = `Want to review the source code that will be installed? Download it here: ${sourceDownloadUri}`; - utils.logBullet(marked(sourceDownloadMsg)); +export function displayExternalServices(spec: ExtensionSpec) { + const lines = + spec.externalServices?.map((service: ExternalService) => { + return ` - ${clc.cyan(`${service.name} (${service.pricingUri})`)}`; + }) ?? []; + return clc.bold("External services used:\n") + lines.join("\n"); +} + +export function displayEvents(spec: ExtensionSpec) { + const lines = + spec.events?.map((event: EventDescriptor) => { + return ` - ${clc.magenta(event.type)}${event.description ? `: ${event.description}` : ""}`; + }) ?? []; + return clc.bold("Events emitted:\n") + lines.join("\n"); +} + +export function displayResources(spec: ExtensionSpec) { + const lines = spec.resources.map((resource: Resource) => { + let type: string = resource.type; + switch (resource.type) { + case "firebaseextensions.v1beta.function": + type = "Cloud Function (1st gen)"; + break; + case "firebaseextensions.v1beta.v2function": + type = "Cloud Function (2nd gen)"; + break; + default: + } + return ` - ${clc.blue(`${resource.name} (${type})`)}${ + resource.description ? `: ${resource.description}` : "" + }`; + }); + lines.push( + ...new Set( + spec.lifecycleEvents?.map((event: LifecycleEvent) => { + return ` - ${clc.blue(`${event.taskQueueTriggerFunction} (Cloud Task queue)`)}`; + }) + ) + ); + lines.push( + ...spec.params + .filter((param: Param) => { + return param.type === "SECRET"; + }) + .map((param: Param) => { + return ` - ${clc.blue(`${param.param} (Cloud Secret Manager secret)`)}`; + }) + ); + return clc.bold("Resources created:\n") + (lines.length ? lines.join("\n") : " - None"); } /** @@ -92,7 +173,7 @@ export function printSourceDownloadLink(sourceDownloadUri: string): void { */ export async function retrieveRoleInfo(role: string) { const res = await iam.getRole(role); - return ` ${res.title} (${res.description})`; + return ` - ${clc.yellow(res.title!)}${res.description ? `: ${res.description}` : ""}`; } async function displayRoles(roles: Role[]): Promise { @@ -101,14 +182,14 @@ async function displayRoles(roles: Role[]): Promise { return retrieveRoleInfo(role.role); }) ); - return clc.bold("**Roles granted to this Extension**:\n") + lines.join("\n"); + return clc.bold("Roles granted:\n") + lines.join("\n"); } function displayApis(apis: Api[]): string { const lines: string[] = apis.map((api: Api) => { - return ` ${api.apiName} (${api.reason})`; + return ` - ${clc.cyan(api.apiName!)}: ${api.reason}`; }); - return "**APIs used by this Extension**:\n" + lines.join("\n"); + return clc.bold("APIs used:\n") + lines.join("\n"); } function usesTasks(spec: ExtensionSpec): boolean { @@ -123,13 +204,13 @@ function impliedRoles(spec: ExtensionSpec): Role[] { if (usesSecrets(spec) && !spec.roles?.some((r: Role) => r.role === SECRET_ROLE)) { roles.push({ role: SECRET_ROLE, - reason: "Allows the extension to read secret values from Cloud Secret Manager", + reason: "Allows the extension to read secret values from Cloud Secret Manager.", }); } if (usesTasks(spec) && !spec.roles?.some((r: Role) => r.role === TASKS_ROLE)) { roles.push({ role: TASKS_ROLE, - reason: "Allows the extension to enqueue Cloud Tasks", + reason: "Allows the extension to enqueue Cloud Tasks.", }); } return roles.concat(spec.roles ?? []); @@ -140,7 +221,7 @@ function impliedApis(spec: ExtensionSpec): Api[] { if (usesTasks(spec) && !spec.apis?.some((a: Api) => a.apiName === TASKS_API)) { apis.push({ apiName: TASKS_API, - reason: "Allows the extension to enqueue Cloud Tasks", + reason: "Allows the extension to enqueue Cloud Tasks.", }); } diff --git a/src/extensions/extensionsHelper.ts b/src/extensions/extensionsHelper.ts index 063d526af9e..b61073423f5 100644 --- a/src/extensions/extensionsHelper.ts +++ b/src/extensions/extensionsHelper.ts @@ -42,7 +42,6 @@ import { envOverride } from "../utils"; import { getLocalChangelog } from "./change-log"; import { getProjectNumber } from "../getProjectNumber"; import { Constants } from "../emulator/constants"; -import { resolveVersion } from "../deploy/extensions/planner"; /** * SpecParamType represents the exact strings that the extensions @@ -1245,25 +1244,3 @@ export async function diagnoseAndFixProject(options: any): Promise { throw new FirebaseError("Unable to proceed until all issues are resolved."); } } - -/** - * Canonicalize a user-inputted ref string. - * 1. Infer firebase publisher if not provided - * 2. Infer "latest-approved" as the version if not provided - */ -export async function canonicalizeRefInput(refInput: string): Promise { - let inferredRef = refInput; - // TODO: Stop defaulting to 'firebase' publisher ID if none provided. - // Infer 'firebase' if publisher ID not provided. - if (refInput.split("/").length < 2) { - inferredRef = `firebase/${inferredRef}`; - } - // Infer 'latest-approved' if no version provided. - if (refInput.split("@").length < 2) { - inferredRef = `${inferredRef}@latest-approved`; - } - // Get the correct version for a given extension reference from the Registry API. - const ref = refs.parse(inferredRef); - ref.version = await resolveVersion(ref); - return refs.toExtensionVersionRef(ref); -} diff --git a/src/extensions/paramHelper.ts b/src/extensions/paramHelper.ts index aca46a91d4d..695410085b2 100644 --- a/src/extensions/paramHelper.ts +++ b/src/extensions/paramHelper.ts @@ -94,7 +94,6 @@ export async function getParams(args: { instanceId: string; paramSpecs: Param[]; nonInteractive?: boolean; - paramsEnvPath?: string; reconfiguring?: boolean; }): Promise> { let params: Record; @@ -118,7 +117,6 @@ export async function getParamsForUpdate(args: { newSpec: ExtensionSpec; currentParams: { [option: string]: string }; projectId?: string; - paramsEnvPath?: string; nonInteractive?: boolean; instanceId: string; }): Promise> { diff --git a/src/extensions/types.ts b/src/extensions/types.ts index a9c06cfe2f4..a2c29ce3137 100644 --- a/src/extensions/types.ts +++ b/src/extensions/types.ts @@ -122,6 +122,12 @@ export interface ExtensionSpec { readmeContent?: string; externalServices?: ExternalService[]; events?: EventDescriptor[]; + lifecycleEvents?: LifecycleEvent[]; +} + +export interface LifecycleEvent { + stage: "STAGE_UNSPECIFIED" | "ON_INSTALL" | "ON_UPDATE" | "ON_CONFIGURE"; + taskQueueTriggerFunction: string; } export interface EventDescriptor { diff --git a/src/extensions/updateHelper.ts b/src/extensions/updateHelper.ts index 521d91cb013..699107bdf3d 100644 --- a/src/extensions/updateHelper.ts +++ b/src/extensions/updateHelper.ts @@ -13,7 +13,7 @@ import { isLocalOrURLPath, } from "./extensionsHelper"; import * as utils from "../utils"; -import { displayExtInfo } from "./displayExtensionInfo"; +import { displayExtensionVersionInfo } from "./displayExtensionInfo"; function invalidSourceErrMsgTemplate(instanceId: string, source: string): string { return `Unable to update from the source \`${clc.bold( @@ -157,7 +157,7 @@ export async function updateFromLocalSource( localSource: string, existingSpec: ExtensionSpec ): Promise { - await displayExtInfo(instanceId, "", existingSpec, false); + await displayExtensionVersionInfo({ spec: existingSpec }); let source; try { source = await createSourceFromLocation(projectId, localSource); @@ -187,7 +187,7 @@ export async function updateFromUrlSource( urlSource: string, existingSpec: ExtensionSpec ): Promise { - await displayExtInfo(instanceId, "", existingSpec, false); + await displayExtensionVersionInfo({ spec: existingSpec }); let source; try { source = await createSourceFromLocation(projectId, urlSource); diff --git a/src/test/deploy/extensions/planner.spec.ts b/src/test/deploy/extensions/planner.spec.ts index b4a6ee757a6..6c082b5bbbb 100644 --- a/src/test/deploy/extensions/planner.spec.ts +++ b/src/test/deploy/extensions/planner.spec.ts @@ -35,7 +35,6 @@ function extensionVersion(version?: string): any { describe("Extensions Deployment Planner", () => { describe("resolveSemver", () => { let listExtensionVersionsStub: sinon.SinonStub; - let getExtensionStub: sinon.SinonStub; before(() => { listExtensionVersionsStub = sinon.stub(extensionsApi, "listExtensionVersions").resolves([ extensionVersion("0.1.0"), @@ -43,14 +42,10 @@ describe("Extensions Deployment Planner", () => { extensionVersion("0.2.0"), extensionVersion(), // Explicitly test that this doesn't break on bad data ]); - getExtensionStub = sinon - .stub(extensionsApi, "getExtension") - .resolves(extension("0.2.0", "0.1.1")); }); after(() => { listExtensionVersionsStub.restore(); - getExtensionStub.restore(); }); const cases = [ @@ -94,19 +89,25 @@ describe("Extensions Deployment Planner", () => { it(c.description, () => { if (!c.err) { expect( - planner.resolveVersion({ - publisherId: "test", - extensionId: "test", - version: c.in, - }) + planner.resolveVersion( + { + publisherId: "test", + extensionId: "test", + version: c.in, + }, + extension("0.2.0", "0.1.1") + ) ).to.eventually.equal(c.out); } else { expect( - planner.resolveVersion({ - publisherId: "test", - extensionId: "test", - version: c.in, - }) + planner.resolveVersion( + { + publisherId: "test", + extensionId: "test", + version: c.in, + }, + extension("0.2.0", "0.1.1") + ) ).to.eventually.be.rejected; } }); diff --git a/src/test/extensions/displayExtensionInfo.spec.ts b/src/test/extensions/displayExtensionInfo.spec.ts index 8057b149dba..7aa8dac1b10 100644 --- a/src/test/extensions/displayExtensionInfo.spec.ts +++ b/src/test/extensions/displayExtensionInfo.spec.ts @@ -3,18 +3,18 @@ import { expect } from "chai"; import * as iam from "../../gcp/iam"; import * as displayExtensionInfo from "../../extensions/displayExtensionInfo"; -import { ExtensionSpec, Param, Resource } from "../../extensions/types"; +import { ExtensionSpec, ExtensionVersion, Resource } from "../../extensions/types"; import { ParamType } from "../../extensions/types"; const SPEC: ExtensionSpec = { name: "test", - displayName: "Old", - description: "descriptive", - version: "0.1.0", + displayName: "My Extension", + description: "My extension's description", + version: "1.0.0", license: "MIT", apis: [ - { apiName: "api1", reason: "" }, - { apiName: "api2", reason: "" }, + { apiName: "api1.googleapis.com", reason: "" }, + { apiName: "api2.googleapis.com", reason: "" }, ], roles: [ { role: "role1", reason: "" }, @@ -23,29 +23,53 @@ const SPEC: ExtensionSpec = { resources: [ { name: "resource1", type: "firebaseextensions.v1beta.function", description: "desc" }, { name: "resource2", type: "other", description: "" } as unknown as Resource, + { + name: "taskResource", + type: "firebaseextensions.v1beta.function", + properties: { + taskQueueTrigger: {}, + }, + }, ], author: { authorName: "Tester", url: "firebase.google.com" }, contributors: [{ authorName: "Tester 2" }], billingRequired: true, sourceUrl: "test.com", - params: [], + params: [ + { + param: "secret", + label: "Secret", + type: ParamType.SECRET, + }, + ], systemParams: [], + events: [ + { + type: "abc.def.my-event", + description: "desc", + }, + ], + lifecycleEvents: [ + { + stage: "ON_INSTALL", + taskQueueTriggerFunction: "taskResource", + }, + ], }; -const TASK_FUNCTION_RESOURCE: Resource = { - name: "taskResource", - type: "firebaseextensions.v1beta.function", - properties: { - taskQueueTrigger: {}, +const EXT_VERSION: ExtensionVersion = { + name: "publishers/pub/extensions/my-ext/versions/1.0.0", + ref: "pub/my-ext@1.0.0", + state: "PUBLISHED", + spec: SPEC, + hash: "abc123", + sourceDownloadUri: "https://google.com", + buildSourceUri: "https://github.com/pub/extensions/my-ext", + listing: { + state: "APPROVED", }, }; -const SECRET_PARAM: Param = { - param: "secret", - label: "Secret", - type: ParamType.SECRET, -}; - describe("displayExtensionInfo", () => { describe("displayExtInfo", () => { let getRoleStub: sinon.SinonStub; @@ -74,91 +98,51 @@ describe("displayExtensionInfo", () => { }); it("should display info during install", async () => { - const loggedLines = await displayExtensionInfo.displayExtInfo(SPEC.name, "", SPEC); - const expected: string[] = [ - "**Name**: Old", - "**Description**: descriptive", - "**APIs used by this Extension**:\n api1 ()\n api2 ()", - "\u001b[1m**Roles granted to this Extension**:\n\u001b[22m Role 1 (a role)\n Role 2 (a role)", - ]; - expect(loggedLines.length).to.eql(expected.length); - expect(loggedLines[0]).to.include("Old"); - expect(loggedLines[1]).to.include("descriptive"); - expect(loggedLines[2]).to.include("api1"); - expect(loggedLines[2]).to.include("api2"); - expect(loggedLines[3]).to.include("Role 1"); - expect(loggedLines[3]).to.include("Role 2"); + const loggedLines = await displayExtensionInfo.displayExtensionVersionInfo({ spec: SPEC }); + expect(loggedLines[0]).to.include(SPEC.displayName); + expect(loggedLines[1]).to.include(SPEC.description); + expect(loggedLines[2]).to.include(SPEC.version); + expect(loggedLines[3]).to.include(SPEC.license); + expect(loggedLines[4]).to.include("resource1 (Cloud Function (1st gen))"); + expect(loggedLines[4]).to.include("resource2 (other)"); + expect(loggedLines[4]).to.include("taskResource (Cloud Function (1st gen))"); + expect(loggedLines[4]).to.include("taskResource (Cloud Task queue)"); + expect(loggedLines[4]).to.include("secret (Cloud Secret Manager secret)"); + expect(loggedLines[5]).to.include("abc.def.my-event"); + expect(loggedLines[6]).to.include("api1.googleapis.com"); + expect(loggedLines[6]).to.include("api1.googleapis.com"); + expect(loggedLines[6]).to.include("cloudtasks.googleapis.com"); + expect(loggedLines[7]).to.include("Role 1"); + expect(loggedLines[7]).to.include("Role 2"); + expect(loggedLines[7]).to.include("Cloud Task Enqueuer"); }); it("should display additional information for a published extension", async () => { - const loggedLines = await displayExtensionInfo.displayExtInfo( - SPEC.name, - "testpublisher", - SPEC, - true - ); - const expected: string[] = [ - "**Name**: Old", - "**Publisher**: testpublisher", - "**Description**: descriptive", - "**License**: MIT", - "**Source code**: test.com", - "**APIs used by this Extension**:\n api1 ()\n api2 ()", - "\u001b[1m**Roles granted to this Extension**:\n\u001b[22m Role 1 (a role)\n Role 2 (a role)", - ]; - expect(loggedLines.length).to.eql(expected.length); - expect(loggedLines[0]).to.include("Old"); - expect(loggedLines[1]).to.include("testpublisher"); - expect(loggedLines[2]).to.include("descriptive"); - expect(loggedLines[3]).to.include("MIT"); - expect(loggedLines[4]).to.include("test.com"); - expect(loggedLines[5]).to.include("api1"); - expect(loggedLines[5]).to.include("api2"); - expect(loggedLines[6]).to.include("Role 1"); - expect(loggedLines[6]).to.include("Role 2"); - }); - - it("should display role and api for Cloud Tasks during install", async () => { - const specWithTasks = JSON.parse(JSON.stringify(SPEC)) as ExtensionSpec; - specWithTasks.resources.push(TASK_FUNCTION_RESOURCE); - - const loggedLines = await displayExtensionInfo.displayExtInfo(SPEC.name, "", specWithTasks); - const expected: string[] = [ - "**Name**: Old", - "**Description**: descriptive", - "**APIs used by this Extension**:\n api1 ()\n api2 ()", - "\u001b[1m**Roles granted to this Extension**:\n\u001b[22m Role 1 (a role)\n Role 2 (a role)\n Cloud Task Enqueuer (Enqueue tasks)", - ]; - expect(loggedLines.length).to.eql(expected.length); - expect(loggedLines[0]).to.include("Old"); - expect(loggedLines[1]).to.include("descriptive"); - expect(loggedLines[2]).to.include("api1"); - expect(loggedLines[2]).to.include("api2"); - expect(loggedLines[2]).to.include("Cloud Tasks"); - expect(loggedLines[3]).to.include("Role 1"); - expect(loggedLines[3]).to.include("Role 2"); - expect(loggedLines[3]).to.include("Cloud Task Enqueuer"); - }); - - it("should display role for Cloud Secret Manager during install", async () => { - const specWithSecret = JSON.parse(JSON.stringify(SPEC)) as ExtensionSpec; - specWithSecret.params.push(SECRET_PARAM); - - const loggedLines = await displayExtensionInfo.displayExtInfo(SPEC.name, "", specWithSecret); - const expected: string[] = [ - "**Name**: Old", - "**Description**: descriptive", - "**APIs used by this Extension**:\n api1 ()\n api2 ()", - "\u001b[1m**Roles granted to this Extension**:\n\u001b[22m Role 1 (a role)\n Role 2 (a role)\n Secret Accessor (Access secrets)", - ]; - expect(loggedLines.length).to.eql(expected.length); - expect(loggedLines[0]).to.include("Old"); - expect(loggedLines[1]).to.include("descriptive"); - expect(loggedLines[2]).to.include("api1"); - expect(loggedLines[2]).to.include("api2"); - expect(loggedLines[3]).to.include("Role 1"); - expect(loggedLines[3]).to.include("Role 2"); - expect(loggedLines[3]).to.include("Secret Accessor"); + const loggedLines = await displayExtensionInfo.displayExtensionVersionInfo({ + spec: SPEC, + extensionVersion: EXT_VERSION, + latestApprovedVersion: "1.0.0", + latestVersion: "1.0.0", + }); + expect(loggedLines[0]).to.include(SPEC.displayName); + expect(loggedLines[1]).to.include(SPEC.description); + expect(loggedLines[2]).to.include(SPEC.version); + expect(loggedLines[3]).to.include("Accepted"); + expect(loggedLines[4]).to.include("View in Extensions Hub"); + expect(loggedLines[5]).to.include(EXT_VERSION.buildSourceUri); + expect(loggedLines[6]).to.include(SPEC.license); + expect(loggedLines[7]).to.include("resource1 (Cloud Function (1st gen))"); + expect(loggedLines[7]).to.include("resource2 (other)"); + expect(loggedLines[7]).to.include("taskResource (Cloud Function (1st gen))"); + expect(loggedLines[7]).to.include("taskResource (Cloud Task queue)"); + expect(loggedLines[7]).to.include("secret (Cloud Secret Manager secret)"); + expect(loggedLines[8]).to.include("abc.def.my-event"); + expect(loggedLines[9]).to.include("api1.googleapis.com"); + expect(loggedLines[9]).to.include("api1.googleapis.com"); + expect(loggedLines[9]).to.include("cloudtasks.googleapis.com"); + expect(loggedLines[10]).to.include("Role 1"); + expect(loggedLines[10]).to.include("Role 2"); + expect(loggedLines[10]).to.include("Cloud Task Enqueuer"); }); }); }); diff --git a/src/test/extensions/extensionsHelper.spec.ts b/src/test/extensions/extensionsHelper.spec.ts index 446890600c6..51c8fab7b99 100644 --- a/src/test/extensions/extensionsHelper.spec.ts +++ b/src/test/extensions/extensionsHelper.spec.ts @@ -22,8 +22,6 @@ import { } from "../../extensions/types"; import { Readable } from "stream"; import { ArchiveResult } from "../../archiveDirectory"; -import { canonicalizeRefInput } from "../../extensions/extensionsHelper"; -import * as planner from "../../deploy/extensions/planner"; describe("extensionsHelper", () => { describe("substituteParams", () => { @@ -1004,37 +1002,4 @@ describe("extensionsHelper", () => { ).to.eql("Prerelease"); }); }); - - describe(`${canonicalizeRefInput.name}`, () => { - let resolveVersionStub: sinon.SinonStub; - beforeEach(() => { - resolveVersionStub = sinon.stub(planner, "resolveVersion").resolves("10.1.1"); - }); - afterEach(() => { - resolveVersionStub.restore(); - }); - it("should do nothing to a valid ref", async () => { - expect(await canonicalizeRefInput("firebase/bigquery-export@10.1.1")).to.equal( - "firebase/bigquery-export@10.1.1" - ); - }); - - it("should infer latest version", async () => { - expect(await canonicalizeRefInput("firebase/bigquery-export")).to.equal( - "firebase/bigquery-export@10.1.1" - ); - }); - - it("should infer publisher name as firebase", async () => { - expect(await canonicalizeRefInput("firebase/bigquery-export")).to.equal( - "firebase/bigquery-export@10.1.1" - ); - }); - - it("should infer publisher name as firebase and also infer latest as version", async () => { - expect(await canonicalizeRefInput("bigquery-export")).to.equal( - "firebase/bigquery-export@10.1.1" - ); - }); - }); }); From 417c4b483ebbbdaf36a21be2da72e0ad098f0b3c Mon Sep 17 00:00:00 2001 From: Sairam Sakhamuri Date: Tue, 27 Jun 2023 16:26:11 -0700 Subject: [PATCH 092/320] Discovery: Added node runtime. (#5993) * Added runtime command discovery * Resolved comments * Added error case to analyse codebase method * Updated install command * Reorganized tests and removed unwated promise.resolve stmt * Added review changes on install command and node version string array * Changes to node.ts to include additional condions on run script * Added code comments to types * Added undefied to return if no cmd * Added undefied to return if no cmd --- .../compose/discover/runtime/node.ts | 212 +++++++++++++++ src/frameworks/compose/discover/types.ts | 2 +- .../compose/discover/runtime/node.spec.ts | 241 ++++++++++++++++++ 3 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 src/frameworks/compose/discover/runtime/node.ts create mode 100644 src/test/frameworks/compose/discover/runtime/node.spec.ts diff --git a/src/frameworks/compose/discover/runtime/node.ts b/src/frameworks/compose/discover/runtime/node.ts new file mode 100644 index 00000000000..976657deac9 --- /dev/null +++ b/src/frameworks/compose/discover/runtime/node.ts @@ -0,0 +1,212 @@ +import { readOrNull } from "../filesystem"; +import { FileSystem, FrameworkSpec, Runtime } from "../types"; +import { RuntimeSpec } from "../types"; +import { frameworkMatcher } from "../frameworkMatcher"; +import { LifecycleCommands } from "../types"; +import { Command } from "../types"; +import { FirebaseError } from "../../../../error"; +import { logger } from "../../../../../src/logger"; +import { conjoinOptions } from "../../../utils"; + +export interface PackageJSON { + dependencies?: Record; + devDependencies?: Record; + scripts?: Record; + engines?: Record; +} +type PackageManager = "npm" | "yarn"; + +const supportedNodeVersions: string[] = ["18"]; +const NODE_RUNTIME_ID = "nodejs"; +const PACKAGE_JSON = "package.json"; +const YARN_LOCK = "yarn.lock"; + +export class NodejsRuntime implements Runtime { + private readonly runtimeRequiredFiles: string[] = [PACKAGE_JSON]; + private readonly contentCache: Record = {}; + + // Checks if the codebase is using Node as runtime. + async match(fs: FileSystem): Promise { + const areAllFilesPresent = await Promise.all( + this.runtimeRequiredFiles.map((file) => fs.exists(file)) + ); + + return areAllFilesPresent.every((present) => present); + } + + getRuntimeName(): string { + return NODE_RUNTIME_ID; + } + + getNodeImage(engine: Record | undefined): string { + // If no version is mentioned explicitly, assuming application is compatible with latest version. + if (!engine || !engine.node) { + return `node:${supportedNodeVersions[supportedNodeVersions.length - 1]}-slim`; + } + const versionNumber = engine.node; + + if (!supportedNodeVersions.includes(versionNumber)) { + throw new FirebaseError( + `This integration expects Node version ${conjoinOptions( + supportedNodeVersions, + "or" + )}. You're running version ${versionNumber}, which is not compatible.` + ); + } + + return `node:${versionNumber}-slim`; + } + + async getPackageManager(fs: FileSystem): Promise { + try { + if (await fs.exists(YARN_LOCK)) { + return "yarn"; + } + + return "npm"; + } catch (error: any) { + logger.error("Failed to check files to identify package manager"); + throw error; + } + } + + getDependencies(packageJSON: PackageJSON): Record { + return { ...packageJSON.dependencies, ...packageJSON.devDependencies }; + } + + packageManagerInstallCommand(packageManager: PackageManager): string | undefined { + const packages: string[] = []; + if (packageManager === "yarn") { + packages.push("yarn"); + } + if (!packages.length) { + return undefined; + } + + return `npm install --global ${packages.join(" ")}`; + } + + installCommand(fs: FileSystem, packageManager: PackageManager): string { + let installCmd = "npm install"; + + if (packageManager === "yarn") { + installCmd = "yarn install"; + } + + return installCmd; + } + + async detectedCommands( + packageManager: PackageManager, + scripts: Record | undefined, + matchedFramework: FrameworkSpec | null, + fs: FileSystem + ): Promise { + return { + build: this.getBuildCommand(packageManager, scripts, matchedFramework), + dev: this.getDevCommand(packageManager, scripts, matchedFramework), + run: await this.getRunCommand(packageManager, scripts, matchedFramework, fs), + }; + } + + executeScript(packageManager: string, scriptName: string): string { + return `${packageManager} run ${scriptName}`; + } + + executeFrameworkCommand(packageManager: PackageManager, command: Command): Command { + if (packageManager === "npm" || packageManager === "yarn") { + command.cmd = "npx " + command.cmd; + } + + return command; + } + + getBuildCommand( + packageManager: PackageManager, + scripts: Record | undefined, + matchedFramework: FrameworkSpec | null + ): Command | undefined { + let buildCommand: Command = { cmd: "" }; + if (scripts?.build) { + buildCommand.cmd = this.executeScript(packageManager, "build"); + } else if (matchedFramework && matchedFramework.commands?.build) { + buildCommand = matchedFramework.commands.build; + buildCommand = this.executeFrameworkCommand(packageManager, buildCommand); + } + + return buildCommand.cmd === "" ? undefined : buildCommand; + } + + getDevCommand( + packageManager: PackageManager, + scripts: Record | undefined, + matchedFramework: FrameworkSpec | null + ): Command | undefined { + let devCommand: Command = { cmd: "", env: { NODE_ENV: "dev" } }; + if (scripts?.dev) { + devCommand.cmd = this.executeScript(packageManager, "dev"); + } else if (matchedFramework && matchedFramework.commands?.dev) { + devCommand = matchedFramework.commands.dev; + devCommand = this.executeFrameworkCommand(packageManager, devCommand); + } + + return devCommand.cmd === "" ? undefined : devCommand; + } + + async getRunCommand( + packageManager: PackageManager, + scripts: Record | undefined, + matchedFramework: FrameworkSpec | null, + fs: FileSystem + ): Promise { + let runCommand: Command = { cmd: "", env: { NODE_ENV: "production" } }; + if (scripts?.start) { + runCommand.cmd = this.executeScript(packageManager, "start"); + } else if (matchedFramework && matchedFramework.commands?.run) { + runCommand = matchedFramework.commands.run; + runCommand = this.executeFrameworkCommand(packageManager, runCommand); + } else if (scripts?.main) { + runCommand.cmd = `node ${scripts.main}`; + } else if (await fs.exists("index.js")) { + runCommand.cmd = `node index.js`; + } + + return runCommand.cmd === "" ? undefined : runCommand; + } + + async analyseCodebase(fs: FileSystem, allFrameworkSpecs: FrameworkSpec[]): Promise { + try { + const packageJSONRaw = await readOrNull(fs, PACKAGE_JSON); + let packageJSON: PackageJSON = {}; + if (packageJSONRaw) { + packageJSON = JSON.parse(packageJSONRaw) as PackageJSON; + } + const packageManager = await this.getPackageManager(fs); + const nodeImage = this.getNodeImage(packageJSON.engines); + const dependencies = this.getDependencies(packageJSON); + const matchedFramework = await frameworkMatcher( + NODE_RUNTIME_ID, + fs, + allFrameworkSpecs, + dependencies + ); + + const runtimeSpec: RuntimeSpec = { + id: NODE_RUNTIME_ID, + baseImage: nodeImage, + packageManagerInstallCommand: this.packageManagerInstallCommand(packageManager), + installCommand: this.installCommand(fs, packageManager), + detectedCommands: await this.detectedCommands( + packageManager, + packageJSON.scripts, + matchedFramework, + fs + ), + }; + + return runtimeSpec; + } catch (error: any) { + throw new FirebaseError(`Failed to parse engine: ${error}`); + } + } +} diff --git a/src/frameworks/compose/discover/types.ts b/src/frameworks/compose/discover/types.ts index 677e054ec27..b919e552c4b 100644 --- a/src/frameworks/compose/discover/types.ts +++ b/src/frameworks/compose/discover/types.ts @@ -6,7 +6,7 @@ export interface FileSystem { export interface Runtime { match(fs: FileSystem): Promise; getRuntimeName(): string; - analyseCodebase(fs: FileSystem, allFrameworkSpecs: FrameworkSpec[]): Promise; + analyseCodebase(fs: FileSystem, allFrameworkSpecs: FrameworkSpec[]): Promise; } export interface Command { diff --git a/src/test/frameworks/compose/discover/runtime/node.spec.ts b/src/test/frameworks/compose/discover/runtime/node.spec.ts new file mode 100644 index 00000000000..b2bbaee767c --- /dev/null +++ b/src/test/frameworks/compose/discover/runtime/node.spec.ts @@ -0,0 +1,241 @@ +import { MockFileSystem } from "../mockFileSystem"; +import { expect } from "chai"; +import { + NodejsRuntime, + PackageJSON, +} from "../../../../../frameworks/compose/discover/runtime/node"; +import { FrameworkSpec } from "../../../../../frameworks/compose/discover/types"; +import { FirebaseError } from "../../../../../error"; + +describe("NodejsRuntime", () => { + let nodeJSRuntime: NodejsRuntime; + let allFrameworks: FrameworkSpec[]; + + before(() => { + nodeJSRuntime = new NodejsRuntime(); + allFrameworks = [ + { + id: "express", + runtime: "nodejs", + requiredDependencies: [{ name: "express" }], + }, + { + id: "next", + runtime: "nodejs", + requiredDependencies: [{ name: "next" }], + requiredFiles: [["next.config.js"], "next.config.ts"], + embedsFrameworks: ["react"], + commands: { + dev: { + cmd: "next dev", + env: { NODE_ENV: "dev" }, + }, + }, + }, + ]; + }); + + describe("getNodeImage", () => { + it("should return a valid node Image", () => { + const version: Record = { + node: "18", + }; + const actualImage = nodeJSRuntime.getNodeImage(version); + const expectedImage = "node:18-slim"; + + expect(actualImage).to.deep.equal(expectedImage); + }); + }); + + describe("getPackageManager", () => { + it("should return yarn package manager", async () => { + const fileSystem = new MockFileSystem({ + "yarn.lock": "It is test file", + }); + const actual = await nodeJSRuntime.getPackageManager(fileSystem); + const expected = "yarn"; + + expect(actual).to.equal(expected); + }); + }); + + describe("getDependencies", () => { + it("should return direct and transitive dependencies", () => { + const packageJSON: PackageJSON = { + dependencies: { + express: "^4.18.2", + }, + devDependencies: { + nodemon: "^2.0.12", + mocha: "^9.1.1", + }, + }; + const actual = nodeJSRuntime.getDependencies(packageJSON); + const expected = { + express: "^4.18.2", + nodemon: "^2.0.12", + mocha: "^9.1.1", + }; + + expect(actual).to.deep.equal(expected); + }); + }); + + describe("detectedCommands", () => { + it("should prepend npx to framework commands", async () => { + const fs = new MockFileSystem({ + "package.json": "Test file", + }); + const matchedFramework: FrameworkSpec = { + id: "next", + runtime: "nodejs", + requiredDependencies: [], + commands: { + dev: { + cmd: "next dev", + env: { NODE_ENV: "dev" }, + }, + }, + }; + const scripts = { + build: "next build", + start: "next start", + }; + + const actual = await nodeJSRuntime.detectedCommands("yarn", scripts, matchedFramework, fs); + const expected = { + build: { + cmd: "yarn run build", + }, + dev: { + cmd: "npx next dev", + env: { NODE_ENV: "dev" }, + }, + run: { + cmd: "yarn run start", + env: { NODE_ENV: "production" }, + }, + }; + + expect(actual).to.deep.equal(expected); + }); + + it("should prefer scripts over framework commands", async () => { + const fs = new MockFileSystem({ + "package.json": "Test file", + }); + const matchedFramework: FrameworkSpec = { + id: "next", + runtime: "nodejs", + requiredDependencies: [], + commands: { + build: { + cmd: "next build testing", + }, + run: { + cmd: "next start testing", + env: { NODE_ENV: "production" }, + }, + dev: { + cmd: "next dev", + env: { NODE_ENV: "dev" }, + }, + }, + }; + const scripts = { + build: "next build", + start: "next start", + }; + + const actual = await nodeJSRuntime.detectedCommands("yarn", scripts, matchedFramework, fs); + const expected = { + build: { + cmd: "yarn run build", + }, + dev: { + cmd: "npx next dev", + env: { NODE_ENV: "dev" }, + }, + run: { + cmd: "yarn run start", + env: { NODE_ENV: "production" }, + }, + }; + + expect(actual).to.deep.equal(expected); + }); + }); + + describe("analyseCodebase", () => { + it("should return runtime specs", async () => { + const fileSystem = new MockFileSystem({ + "next.config.js": "For testing", + "next.config.ts": "For testing", + "package.json": JSON.stringify({ + scripts: { + build: "next build", + start: "next start", + }, + dependencies: { + next: "13.4.5", + react: "18.2.0", + }, + engines: { + node: "18", + }, + }), + }); + + const actual = await nodeJSRuntime.analyseCodebase(fileSystem, allFrameworks); + const expected = { + id: "nodejs", + baseImage: "node:18-slim", + packageManagerInstallCommand: undefined, + installCommand: "npm install", + detectedCommands: { + build: { + cmd: "npm run build", + }, + dev: { + cmd: "npx next dev", + env: { NODE_ENV: "dev" }, + }, + run: { + cmd: "npm run start", + env: { NODE_ENV: "production" }, + }, + }, + }; + + expect(actual).to.deep.equal(expected); + }); + + it("should return error", async () => { + const fileSystem = new MockFileSystem({ + "next.config.js": "For testing purpose.", + "next.config.ts": "For testing purpose.", + "package.json": JSON.stringify({ + scripts: { + build: "next build", + start: "next start", + }, + dependencies: { + // Having both express and next as dependencies. + express: "2.0.8", + next: "13.4.5", + react: "18.2.0", + }, + engines: { + node: "18", + }, + }), + }); + + // Failed with multiple framework matches + await expect(nodeJSRuntime.analyseCodebase(fileSystem, allFrameworks)).to.be.rejectedWith( + FirebaseError, + "Failed to parse engine" + ); + }); + }); +}); From ac28f26b3a8525e239a41f60afef49b0fc35aa38 Mon Sep 17 00:00:00 2001 From: Pavel Jbanov Date: Wed, 28 Jun 2023 10:18:30 -0400 Subject: [PATCH 093/320] Increased create extensions instance timeout to 1h to match the backend (#5969) --- CHANGELOG.md | 1 + src/extensions/extensionsApi.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2668eb75f0f..0ddb4feca9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ +- Increased extension instance create poll timeout to 1h to match backend (#5969). - Refactored `ext:install` to use the latest extension metadata. (#5997) diff --git a/src/extensions/extensionsApi.ts b/src/extensions/extensionsApi.ts index bcb50764faf..1ec8b140028 100644 --- a/src/extensions/extensionsApi.ts +++ b/src/extensions/extensionsApi.ts @@ -58,7 +58,7 @@ async function createInstanceHelper( apiOrigin: extensionsOrigin, apiVersion: EXTENSIONS_API_VERSION, operationResourceName: createRes.body.name, - masterTimeout: 600000, + masterTimeout: 3600000, }); return pollRes; } From 654e88483bb650b2544024d8232d7091867e5cdb Mon Sep 17 00:00:00 2001 From: Alex Pascal Date: Wed, 28 Jun 2023 11:50:54 -0700 Subject: [PATCH 094/320] Normalized extension root path before usage in ext:dev:upload. (#6054) * Normalized extension root path before usage. * Update CHANGELOG.md * Update publisherApi.ts * Update extensionsHelper.ts * Update CHANGELOG.md * Replaced join() with normalize() and fixed regex. * Update extensionsHelper.ts * Update extensionsHelper.ts --- CHANGELOG.md | 1 + src/extensions/extensionsHelper.ts | 31 +++++++++++++++--------------- src/extensions/publisherApi.ts | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ddb4feca9c..5484a42cfb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,3 @@ - Increased extension instance create poll timeout to 1h to match backend (#5969). - Refactored `ext:install` to use the latest extension metadata. (#5997) +- Normalized extension root path before usage in `ext:dev:upload`. (#6054) diff --git a/src/extensions/extensionsHelper.ts b/src/extensions/extensionsHelper.ts index b61073423f5..a5025142fe7 100644 --- a/src/extensions/extensionsHelper.ts +++ b/src/extensions/extensionsHelper.ts @@ -408,24 +408,17 @@ export async function promptForValidRepoURI(): Promise { } /** - * Prompts for a valid extension root. + * Prompts for an extension root. * * @param defaultRoot the default extension root */ -export async function promptForValidExtensionRoot(defaultRoot: string): Promise { - let rootIsValid = false; - let extensionRoot = ""; - while (!rootIsValid) { - extensionRoot = await promptOnce({ - type: "input", - message: - "Enter this extension's root directory in the repo (defaults to previous root if set):", - default: defaultRoot, - }); - // TODO: Add real directory path validation. - rootIsValid = true; - } - return extensionRoot; +export async function promptForExtensionRoot(defaultRoot: string): Promise { + return await promptOnce({ + type: "input", + message: + "Enter this extension's root directory in the repo (defaults to previous root if set):", + default: defaultRoot, + }); } /** @@ -817,11 +810,17 @@ export async function uploadExtensionVersionFromGitHubSource(args: { if (!extensionRoot) { const defaultRoot = "/"; if (!args.nonInteractive) { - extensionRoot = await promptForValidExtensionRoot(defaultRoot); + extensionRoot = await promptForExtensionRoot(defaultRoot); } else { extensionRoot = defaultRoot; } } + // Normalize root path and strip leading and trailing slashes and all `../`. + const normalizedRoot = path + .normalize(extensionRoot) + .replaceAll(/^\/|\/$/g, "") + .replaceAll(/^(\.\.\/)*/g, ""); + extensionRoot = normalizedRoot || "/"; // Prompt for source ref and default to HEAD. let sourceRef = args.sourceRef; diff --git a/src/extensions/publisherApi.ts b/src/extensions/publisherApi.ts index 877ccac7198..b1caa6f177f 100644 --- a/src/extensions/publisherApi.ts +++ b/src/extensions/publisherApi.ts @@ -205,7 +205,7 @@ export async function createExtensionVersionFromGitHubSource(args: { ExtensionVersion >(`/${refs.toExtensionName(ref)}/versions:createFromSource`, { versionId: ref.version, - extensionRoot: args.extensionRoot ?? "/", + extensionRoot: args.extensionRoot || "/", githubRepositorySource: { uri: args.repoUri, sourceRef: args.sourceRef, From 197506a739b83dc7ca5ceaef6bb94d1be520676a Mon Sep 17 00:00:00 2001 From: blidd-google <112491344+blidd-google@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:05:00 -0400 Subject: [PATCH 095/320] Migrates functions metrics to GA4 (#6053) * track functions metrics with ga4 * remove old track() calls --- src/deploy/functions/args.ts | 14 ++ src/deploy/functions/build.ts | 2 + src/deploy/functions/ensure.ts | 3 - src/deploy/functions/prepare.ts | 35 ++-- src/deploy/functions/release/index.ts | 2 +- src/deploy/functions/release/reporter.ts | 77 +++++---- .../node/parseRuntimeAndValidateSDK.ts | 3 - .../functions/runtimes/node/versioning.ts | 2 - .../deploy/functions/release/reporter.spec.ts | 163 +++++++++--------- src/track.ts | 5 +- 10 files changed, 159 insertions(+), 147 deletions(-) diff --git a/src/deploy/functions/args.ts b/src/deploy/functions/args.ts index 1138b9d9491..bc6e1e21db8 100644 --- a/src/deploy/functions/args.ts +++ b/src/deploy/functions/args.ts @@ -2,6 +2,7 @@ import * as backend from "./backend"; import * as gcfV2 from "../../gcp/cloudfunctionsv2"; import * as projectConfig from "../../functions/projectConfig"; import * as deployHelper from "./functionsDeployHelper"; +import { Runtime } from "./runtimes"; // These types should probably be in a root deploy.ts, but we can only boil the ocean one bit at a time. interface CodebasePayload { @@ -49,6 +50,19 @@ export interface Context { gcfV1: string[]; gcfV2: string[]; }; + + // Tracks metrics about codebase deployments to send to GA4 + codebaseDeployEvents?: Record; +} + +export interface CodebaseDeployEvent { + params?: "env_only" | "with_secrets" | "none"; + runtime?: Runtime; + runtime_notice?: string; + fn_deploy_num_successes: number; + fn_deploy_num_failures: number; + fn_deploy_num_canceled: number; + fn_deploy_num_skipped: number; } export interface FirebaseConfig { diff --git a/src/deploy/functions/build.ts b/src/deploy/functions/build.ts index 222b0a75d4e..846a49043b3 100644 --- a/src/deploy/functions/build.ts +++ b/src/deploy/functions/build.ts @@ -6,12 +6,14 @@ import { FirebaseError } from "../../error"; import { assertExhaustive, mapObject, nullsafeVisitor } from "../../functional"; import { UserEnvsOpts, writeUserEnvs } from "../../functions/env"; import { FirebaseConfig } from "./args"; +import { Runtime } from "./runtimes"; /* The union of a customer-controlled deployment and potentially deploy-time defined parameters */ export interface Build { requiredAPIs: RequiredApi[]; endpoints: Record; params: params.Param[]; + runtime?: Runtime; } /** diff --git a/src/deploy/functions/ensure.ts b/src/deploy/functions/ensure.ts index b48740bd748..7006e872af0 100644 --- a/src/deploy/functions/ensure.ts +++ b/src/deploy/functions/ensure.ts @@ -8,7 +8,6 @@ import { logLabeledBullet, logLabeledSuccess } from "../../utils"; import { ensureServiceAgentRole } from "../../gcp/secretManager"; import { getFirebaseProject } from "../../management/projects"; import { assertExhaustive } from "../../functional"; -import { track } from "../../track"; import * as backend from "./backend"; const FAQ_URL = "https://firebase.google.com/support/faq#functions-runtime"; @@ -37,7 +36,6 @@ export async function defaultServiceAccount(e: backend.Endpoint): Promise): boolean { - // "firebase" key is always going to exist in runtime config. - // If any other key exists, we can assume that user is using runtime config. - return Object.keys(config).length > 1; -} /** * Prepare functions codebases for deploy. @@ -88,6 +82,8 @@ export async function prepare( runtimeConfig = { ...runtimeConfig, ...(await getFunctionsConfig(projectId)) }; } + context.codebaseDeployEvents = {}; + // ===Phase 1. Load codebases from source. const wantBuilds = await loadCodebases( context.config, @@ -155,15 +151,23 @@ export async function prepare( codebaseUsesEnvs.push(codebase); } + context.codebaseDeployEvents[codebase] = { + fn_deploy_num_successes: 0, + fn_deploy_num_failures: 0, + fn_deploy_num_canceled: 0, + fn_deploy_num_skipped: 0, + }; + if (wantBuild.params.length > 0) { if (wantBuild.params.every((p) => p.type !== "secret")) { - void track("functions_params_in_build", "env_only"); + context.codebaseDeployEvents[codebase].params = "env_only"; } else { - void track("functions_params_in_build", "with_secrets"); + context.codebaseDeployEvents[codebase].params = "with_secrets"; } } else { - void track("functions_params_in_build", "none"); + context.codebaseDeployEvents[codebase].params = "none"; } + context.codebaseDeployEvents[codebase].runtime = wantBuild.runtime; } // ===Phase 2.5. Before proceeding further, let's make sure that we don't have conflicting function names. @@ -214,18 +218,6 @@ export async function prepare( inferBlockingDetails(wantBackend); } - const tag = hasUserConfig(runtimeConfig) - ? codebaseUsesEnvs.length > 0 - ? "mixed" - : "runtime_config" - : codebaseUsesEnvs.length > 0 - ? "dotenv" - : "none"; - void track("functions_codebase_deploy_env_method", tag); - - const codebaseCnt = Object.keys(payload.functions).length; - void track("functions_codebase_deploy_count", codebaseCnt >= 5 ? "5+" : codebaseCnt.toString()); - // ===Phase 5. Enable APIs required by the deploying backends. const wantBackend = backend.merge(...Object.values(wantBackends)); const haveBackend = backend.merge(...Object.values(haveBackends)); @@ -468,6 +460,7 @@ export async function loadCodebases( // in order for .init() calls to succeed. GOOGLE_CLOUD_QUOTA_PROJECT: projectId, }); + wantBuilds[codebase].runtime = codebaseConfig.runtime; } return wantBuilds; } diff --git a/src/deploy/functions/release/index.ts b/src/deploy/functions/release/index.ts index 08c46191304..e32749feda8 100644 --- a/src/deploy/functions/release/index.ts +++ b/src/deploy/functions/release/index.ts @@ -76,7 +76,7 @@ export async function release( const summary = await fab.applyPlan(plan); - await reporter.logAndTrackDeployStats(summary); + await reporter.logAndTrackDeployStats(summary, context); reporter.printErrors(summary); // N.B. Fabricator::applyPlan updates the endpoints it deploys to include the diff --git a/src/deploy/functions/release/reporter.ts b/src/deploy/functions/release/reporter.ts index 61611c0a7ba..10a4a64757c 100644 --- a/src/deploy/functions/release/reporter.ts +++ b/src/deploy/functions/release/reporter.ts @@ -1,8 +1,9 @@ import * as backend from "../backend"; import * as clc from "colorette"; +import * as args from "../args"; import { logger } from "../../../logger"; -import { track } from "../../../track"; +import { trackGA4 } from "../../../track"; import * as utils from "../../../utils"; import { getFunctionLabel } from "../functionsDeployHelper"; @@ -56,7 +57,10 @@ export class AbortedDeploymentError extends DeploymentError { } /** Add debugger logs and GA metrics for deploy stats. */ -export async function logAndTrackDeployStats(summary: Summary): Promise { +export async function logAndTrackDeployStats( + summary: Summary, + context?: args.Context +): Promise { let totalTime = 0; let totalErrors = 0; let totalSuccesses = 0; @@ -64,54 +68,65 @@ export async function logAndTrackDeployStats(summary: Summary): Promise { const reports: Array> = []; const regions = new Set(); + const codebases = new Set(); for (const result of summary.results) { - const tag = triggerTag(result.endpoint); + const fnDeployEvent = { + platform: result.endpoint.platform, + trigger_type: backend.endpointTriggerType(result.endpoint), + region: result.endpoint.region, + runtime: result.endpoint.runtime, + status: !result.error + ? "success" + : result.error instanceof AbortedDeploymentError + ? "aborted" + : "failure", + duration: result.durationMs, + }; + reports.push(trackGA4("function_deploy", fnDeployEvent)); + regions.add(result.endpoint.region); + codebases.add(result.endpoint.codebase || "default"); totalTime += result.durationMs; if (!result.error) { totalSuccesses++; - reports.push(track("function_deploy_success", tag, result.durationMs)); + if (context?.codebaseDeployEvents?.[result.endpoint.codebase || "default"] !== undefined) { + context.codebaseDeployEvents[result.endpoint.codebase || "default"] + .fn_deploy_num_successes++; + } } else if (result.error instanceof AbortedDeploymentError) { totalAborts++; - reports.push(track("function_deploy_abort", tag, result.durationMs)); + if (context?.codebaseDeployEvents?.[result.endpoint.codebase || "default"] !== undefined) { + context.codebaseDeployEvents[result.endpoint.codebase || "default"] + .fn_deploy_num_canceled++; + } } else { totalErrors++; - reports.push(track("function_deploy_failure", tag, result.durationMs)); + if (context?.codebaseDeployEvents?.[result.endpoint.codebase || "default"] !== undefined) { + context.codebaseDeployEvents[result.endpoint.codebase || "default"] + .fn_deploy_num_failures++; + } } } - const regionCountTag = regions.size < 5 ? regions.size.toString() : ">=5"; - reports.push(track("functions_region_count", regionCountTag, 1)); - - const gcfv1 = summary.results.find((r) => r.endpoint.platform === "gcfv1"); - const gcfv2 = summary.results.find((r) => r.endpoint.platform === "gcfv2"); - const tag = gcfv1 && gcfv2 ? "v1+v2" : gcfv1 ? "v1" : "v2"; - reports.push(track("functions_codebase_deploy", tag, summary.results.length)); + for (const codebase of codebases) { + if (context?.codebaseDeployEvents) { + reports.push(trackGA4("codebase_deploy", { ...context.codebaseDeployEvents[codebase] })); + } + } + const fnDeployGroupEvent = { + codebase_deploy_count: codebases.size >= 5 ? "5+" : codebases.size.toString(), + fn_deploy_num_successes: totalSuccesses, + fn_deploy_num_canceled: totalAborts, + fn_deploy_num_failures: totalErrors, + }; + reports.push(trackGA4("function_deploy_group", fnDeployGroupEvent)); const avgTime = totalTime / (totalSuccesses + totalErrors); - logger.debug(`Total Function Deployment time: ${summary.totalTime}`); logger.debug(`${totalErrors + totalSuccesses + totalAborts} Functions Deployed`); logger.debug(`${totalErrors} Functions Errored`); logger.debug(`${totalAborts} Function Deployments Aborted`); logger.debug(`Average Function Deployment time: ${avgTime}`); - if (totalErrors + totalSuccesses > 0) { - if (totalErrors === 0) { - reports.push(track("functions_deploy_result", "success", totalSuccesses)); - } else if (totalSuccesses > 0) { - reports.push(track("functions_deploy_result", "partial_success", totalSuccesses)); - reports.push(track("functions_deploy_result", "partial_failure", totalErrors)); - reports.push( - track( - "functions_deploy_result", - "partial_error_ratio", - totalErrors / (totalSuccesses + totalErrors) - ) - ); - } else { - reports.push(track("functions_deploy_result", "failure", totalErrors)); - } - } await utils.allSettled(reports); } diff --git a/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts b/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts index 4ce21970fa8..58fd94e9a2c 100644 --- a/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts +++ b/src/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.ts @@ -2,7 +2,6 @@ import * as path from "path"; import * as clc from "colorette"; import { FirebaseError } from "../../../../error"; -import { track } from "../../../../track"; import * as runtimes from "../../runtimes"; // have to require this because no @types/cjson available @@ -80,7 +79,6 @@ export function getRuntimeChoice(sourceDir: string, runtimeFromConfig?: string): : UNSUPPORTED_NODE_VERSION_PACKAGE_JSON_MSG) + DEPRECATED_NODE_VERSION_INFO; if (!runtime || !ENGINE_RUNTIMES_NAMES.includes(runtime)) { - void track("functions_runtime_notices", "package_missing_runtime"); throw new FirebaseError(errorMessage, { exit: 1 }); } @@ -88,7 +86,6 @@ export function getRuntimeChoice(sourceDir: string, runtimeFromConfig?: string): // it's in ENGINE_RUNTIME_NAMES and not in DEPRECATED_RUNTIMES. This is still a // good defense in depth and also lets us upcast the response to Runtime safely. if (runtimes.isDeprecatedRuntime(runtime) || !runtimes.isValidRuntime(runtime)) { - void track("functions_runtime_notices", `${runtime}_deploy_prohibited`); throw new FirebaseError(errorMessage, { exit: 1 }); } diff --git a/src/deploy/functions/runtimes/node/versioning.ts b/src/deploy/functions/runtimes/node/versioning.ts index d0c400c9bbb..4945309c11f 100644 --- a/src/deploy/functions/runtimes/node/versioning.ts +++ b/src/deploy/functions/runtimes/node/versioning.ts @@ -6,7 +6,6 @@ import * as spawn from "cross-spawn"; import * as semver from "semver"; import { logger } from "../../../../logger"; -import { track } from "../../../../track"; import * as utils from "../../../../utils"; interface NpmShowResult { @@ -113,7 +112,6 @@ export function getLatestSDKVersion(): string | undefined { export function checkFunctionsSDKVersion(currentVersion: string): void { try { if (semver.lt(currentVersion, MIN_SDK_VERSION)) { - void track("functions_runtime_notices", "functions_sdk_too_old"); utils.logWarning(FUNCTIONS_SDK_VERSION_TOO_OLD_WARNING); } diff --git a/src/test/deploy/functions/release/reporter.spec.ts b/src/test/deploy/functions/release/reporter.spec.ts index ae2de5cd3f2..b18fee9f728 100644 --- a/src/test/deploy/functions/release/reporter.spec.ts +++ b/src/test/deploy/functions/release/reporter.spec.ts @@ -6,6 +6,7 @@ import * as backend from "../../../../deploy/functions/backend"; import * as reporter from "../../../../deploy/functions/release/reporter"; import * as track from "../../../../track"; import * as events from "../../../../functions/events"; +import * as args from "../../../../deploy/functions/args"; const ENDPOINT_BASE: Omit = { platform: "gcfv1", @@ -117,11 +118,11 @@ describe("reporter", () => { }); describe("logAndTrackDeployStats", () => { - let trackStub: sinon.SinonStub; + let trackGA4Stub: sinon.SinonStub; let debugStub: sinon.SinonStub; beforeEach(() => { - trackStub = sinon.stub(track, "track"); + trackGA4Stub = sinon.stub(track, "trackGA4"); debugStub = sinon.stub(logger, "debug"); }); @@ -134,105 +135,97 @@ describe("reporter", () => { totalTime: 2_000, results: [ { - endpoint: ENDPOINT, + endpoint: { ...ENDPOINT, codebase: "codebase0" }, durationMs: 2_000, }, { - endpoint: ENDPOINT, + endpoint: { ...ENDPOINT, codebase: "codebase1" }, durationMs: 1_000, - error: new reporter.DeploymentError(ENDPOINT, "update", undefined), + error: new reporter.DeploymentError( + { ...ENDPOINT, codebase: "codebase1" }, + "update", + undefined + ), }, { - endpoint: ENDPOINT, + endpoint: { ...ENDPOINT, codebase: "codebase1" }, durationMs: 0, - error: new reporter.AbortedDeploymentError(ENDPOINT), + error: new reporter.AbortedDeploymentError({ ...ENDPOINT, codebase: "codebase1" }), }, ], }; - await reporter.logAndTrackDeployStats(summary); - - expect(trackStub).to.have.been.calledWith("functions_region_count", "1", 1); - expect(trackStub).to.have.been.calledWith("function_deploy_success", "v1.https", 2_000); - expect(trackStub).to.have.been.calledWith("function_deploy_failure", "v1.https", 1_000); - // Aborts aren't tracked because they would throw off timing metrics - expect(trackStub).to.not.have.been.calledWith("function_deploy_failure", "v1.https", 0); - - expect(debugStub).to.have.been.calledWith("Total Function Deployment time: 2000"); - expect(debugStub).to.have.been.calledWith("3 Functions Deployed"); - expect(debugStub).to.have.been.calledWith("1 Functions Errored"); - expect(debugStub).to.have.been.calledWith("1 Function Deployments Aborted"); - - // The 0ms for an aborted function isn't counted. - expect(debugStub).to.have.been.calledWith("Average Function Deployment time: 1500"); - }); - - it("tracks v1 vs v2 codebases", async () => { - const v1 = { ...ENDPOINT }; - const v2: backend.Endpoint = { ...ENDPOINT, platform: "gcfv2" }; - - const summary: reporter.Summary = { - totalTime: 1_000, - results: [ - { - endpoint: v1, - durationMs: 1_000, + const context: args.Context = { + projectId: "id", + codebaseDeployEvents: { + codebase0: { + params: "none", + fn_deploy_num_successes: 0, + fn_deploy_num_canceled: 0, + fn_deploy_num_failures: 0, + fn_deploy_num_skipped: 0, }, - { - endpoint: v2, - durationMs: 1_000, + codebase1: { + params: "none", + fn_deploy_num_successes: 0, + fn_deploy_num_canceled: 0, + fn_deploy_num_failures: 0, + fn_deploy_num_skipped: 0, }, - ], - }; - - await reporter.logAndTrackDeployStats(summary); - expect(trackStub).to.have.been.calledWith("functions_codebase_deploy", "v1+v2", 2); - trackStub.resetHistory(); - - summary.results = [{ endpoint: v1, durationMs: 1_000 }]; - await reporter.logAndTrackDeployStats(summary); - expect(trackStub).to.have.been.calledWith("functions_codebase_deploy", "v1", 1); - trackStub.resetHistory(); - - summary.results = [{ endpoint: v2, durationMs: 1_000 }]; - await reporter.logAndTrackDeployStats(summary); - expect(trackStub).to.have.been.calledWith("functions_codebase_deploy", "v2", 1); - }); - - it("tracks overall success/failure", async () => { - const success: reporter.DeployResult = { - endpoint: ENDPOINT, - durationMs: 1_000, - }; - const failure: reporter.DeployResult = { - endpoint: ENDPOINT, - durationMs: 1_000, - error: new reporter.DeploymentError(ENDPOINT, "create", undefined), + }, }; - const summary: reporter.Summary = { - totalTime: 1_000, - results: [success, failure], - }; + await reporter.logAndTrackDeployStats(summary, context); + + expect(trackGA4Stub).to.have.been.calledWith("function_deploy", { + platform: "gcfv1", + trigger_type: "https", + region: "region", + runtime: "nodejs16", + status: "success", + duration: 2_000, + }); + expect(trackGA4Stub).to.have.been.calledWith("function_deploy", { + platform: "gcfv1", + trigger_type: "https", + region: "region", + runtime: "nodejs16", + status: "failure", + duration: 1_000, + }); + expect(trackGA4Stub).to.have.been.calledWith("function_deploy", { + platform: "gcfv1", + trigger_type: "https", + region: "region", + runtime: "nodejs16", + status: "aborted", + duration: 0, + }); + + expect(trackGA4Stub).to.have.been.calledWith("codebase_deploy", { + params: "none", + fn_deploy_num_successes: 1, + fn_deploy_num_canceled: 0, + fn_deploy_num_failures: 0, + fn_deploy_num_skipped: 0, + }); + expect(trackGA4Stub).to.have.been.calledWith("codebase_deploy", { + params: "none", + fn_deploy_num_successes: 0, + fn_deploy_num_canceled: 1, + fn_deploy_num_failures: 1, + fn_deploy_num_skipped: 0, + }); + + expect(trackGA4Stub).to.have.been.calledWith("function_deploy_group", { + codebase_deploy_count: "2", + fn_deploy_num_successes: 1, + fn_deploy_num_canceled: 1, + fn_deploy_num_failures: 1, + }); - await reporter.logAndTrackDeployStats(summary); - expect(trackStub).to.have.been.calledWith("functions_deploy_result", "partial_success", 1); - expect(trackStub).to.have.been.calledWith("functions_deploy_result", "partial_failure", 1); - expect(trackStub).to.have.been.calledWith( - "functions_deploy_result", - "partial_error_ratio", - 0.5 - ); - trackStub.resetHistory(); - - summary.results = [success]; - await reporter.logAndTrackDeployStats(summary); - expect(trackStub).to.have.been.calledWith("functions_deploy_result", "success", 1); - trackStub.resetHistory(); - - summary.results = [failure]; - await reporter.logAndTrackDeployStats(summary); - expect(trackStub).to.have.been.calledWith("functions_deploy_result", "failure", 1); + // The 0ms for an aborted function isn't counted. + expect(debugStub).to.have.been.calledWith("Average Function Deployment time: 1500"); }); }); diff --git a/src/track.ts b/src/track.ts index 69a0c92f4bd..3f523752d5e 100644 --- a/src/track.ts +++ b/src/track.ts @@ -16,7 +16,10 @@ type cliEventNames = | "hosting_version" | "extension_added_to_manifest" | "extensions_deploy" - | "extensions_emulated"; + | "extensions_emulated" + | "function_deploy" + | "codebase_deploy" + | "function_deploy_group"; type GA4Property = "cli" | "emulator"; interface GA4Info { measurementId: string; From 4db12d24cedca401a18beb60113c6168397fccc3 Mon Sep 17 00:00:00 2001 From: joehan Date: Wed, 28 Jun 2023 12:36:46 -0700 Subject: [PATCH 096/320] Fix incorrect warnings when emulating extensions with httpsTriggers (#6055) --- CHANGELOG.md | 1 + src/extensions/emulator/triggerHelper.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5484a42cfb7..9bf9b02b194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ - Increased extension instance create poll timeout to 1h to match backend (#5969). - Refactored `ext:install` to use the latest extension metadata. (#5997) +- Fixed issue where missing trigger warnings would be wrongly displayed when emulating extensions with HTTPS triggers. (#6055) - Normalized extension root path before usage in `ext:dev:upload`. (#6054) diff --git a/src/extensions/emulator/triggerHelper.ts b/src/extensions/emulator/triggerHelper.ts index 12d2a150d47..ef2f197d1d8 100644 --- a/src/extensions/emulator/triggerHelper.ts +++ b/src/extensions/emulator/triggerHelper.ts @@ -77,7 +77,8 @@ export function functionResourceToEmulatedTriggerDefintion( proto.convertIfPresent(etd, properties, "timeoutSeconds", "timeout", proto.secondsFromDuration); proto.convertIfPresent(etd, properties, "regions", "location", (str: string) => [str]); proto.copyIfPresent(etd, properties, "availableMemoryMb"); - if (properties.httpsTrigger) { + if (properties.httpsTrigger !== undefined) { + // Need to explcitly check undefined since {} is falsey etd.httpsTrigger = properties.httpsTrigger; } if (properties.eventTrigger) { From 893971ffc3bf25dcd7dd8dd022b6163012b90229 Mon Sep 17 00:00:00 2001 From: joehan Date: Wed, 28 Jun 2023 13:22:31 -0700 Subject: [PATCH 097/320] Only record metrics if user confirms ext:install (#6047) * Only record metrics if user confirms ext:install * format --- src/commands/ext-install.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/commands/ext-install.ts b/src/commands/ext-install.ts index 4e722975a17..1b032cd28c7 100644 --- a/src/commands/ext-install.ts +++ b/src/commands/ext-install.ts @@ -73,20 +73,12 @@ export const command = new Command("ext:install [extensionRef]") // Should parse spec locally so we don't need project ID. source = await createSourceFromLocation(needProjectId({ projectId }), extensionRef); await displayExtensionVersionInfo({ spec: source.spec }); - void trackGA4("extension_added_to_manifest", { - published: "local", - interactive: options.nonInteractive ? "false" : "true", - }); } else { const extension = await extensionsApi.getExtension(extensionRef); const ref = refs.parse(extensionRef); ref.version = await resolveVersion(ref, extension); const extensionVersionRef = refs.toExtensionVersionRef(ref); extensionVersion = await extensionsApi.getExtensionVersion(extensionVersionRef); - void trackGA4("extension_added_to_manifest", { - published: extensionVersion.listing?.state === "APPROVED" ? "published" : "uploaded", - interactive: options.nonInteractive ? "false" : "true", - }); await displayExtensionVersionInfo({ spec: extensionVersion.spec, extensionVersion, @@ -143,6 +135,19 @@ export const command = new Command("ext:install [extensionRef]") )}'. Please make sure this is a valid extension and try again.` ); } + + if (source) { + void trackGA4("extension_added_to_manifest", { + published: "local", + interactive: options.nonInteractive ? "false" : "true", + }); + } else if (extensionVersion) { + void trackGA4("extension_added_to_manifest", { + published: extensionVersion.listing?.state === "APPROVED" ? "published" : "uploaded", + interactive: options.nonInteractive ? "false" : "true", + }); + } + try { return installToManifest({ projectId, From e1f0d8db6e01520d4c2c3b54b8ebd131ca82ff25 Mon Sep 17 00:00:00 2001 From: Alex Pascal Date: Wed, 28 Jun 2023 13:35:34 -0700 Subject: [PATCH 098/320] Added descriptive error when repo is private or not found during ext:dev:upload. (#6052) * Added more descriptive error message when repo is private (or not found). * Formatting. * Formatting. * Update CHANGELOG.md --------- Co-authored-by: joehan --- CHANGELOG.md | 1 + src/extensions/extensionsHelper.ts | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bf9b02b194..026e7b69d48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ - Increased extension instance create poll timeout to 1h to match backend (#5969). - Refactored `ext:install` to use the latest extension metadata. (#5997) +- Added descriptive error when repo is private or not found during `ext:dev:upload`. (#6052) - Fixed issue where missing trigger warnings would be wrongly displayed when emulating extensions with HTTPS triggers. (#6055) - Normalized extension root path before usage in `ext:dev:upload`. (#6054) diff --git a/src/extensions/extensionsHelper.ts b/src/extensions/extensionsHelper.ts index a5025142fe7..46b363e0a56 100644 --- a/src/extensions/extensionsHelper.ts +++ b/src/extensions/extensionsHelper.ts @@ -729,17 +729,21 @@ async function fetchExtensionSource( logger.info(`Validating source code at ${clc.bold(sourceUri)}...`); const archiveUri = `${repoUri}/archive/${sourceRef}.zip`; const tempDirectory = tmp.dirSync({ unsafeCleanup: true }); + const archiveErrorMessage = `Failed to extract archive from ${clc.bold( + archiveUri + )}. Please check that the repo is public and that the source ref is valid.`; try { const response = await fetch(archiveUri); if (response.ok) { await response.body.pipe(createUnzipTransform(tempDirectory.name)).promise(); } } catch (err: any) { - throw new FirebaseError( - `Failed to fetch extension archive from ${archiveUri}. Please check the repo URI and source ref. ${err}` - ); + throw new FirebaseError(archiveErrorMessage); } const archiveName = fs.readdirSync(tempDirectory.name)[0]; + if (!archiveName) { + throw new FirebaseError(archiveErrorMessage); + } const rootDirectory = path.join(tempDirectory.name, archiveName, extensionRoot); // Pre-validation to show a more useful error message in the context of a temp directory. try { From 0bcee86d985be40abb39e47ee869a1b299c7d499 Mon Sep 17 00:00:00 2001 From: Dominic Bartl Date: Wed, 28 Jun 2023 22:44:18 +0200 Subject: [PATCH 099/320] Allow $schema property in firebase.json (#6051) * Allow $schema property in firebase.json * Add $schema property via firebaseConfig.ts --------- Co-authored-by: joehan --- schema/firebase-config.json | 4 ++++ src/firebaseConfig.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/schema/firebase-config.json b/schema/firebase-config.json index ca1f66754b1..b4bb9139591 100644 --- a/schema/firebase-config.json +++ b/schema/firebase-config.json @@ -128,6 +128,10 @@ } }, "properties": { + "$schema": { + "format": "uri", + "type": "string" + }, "database": { "anyOf": [ { diff --git a/src/firebaseConfig.ts b/src/firebaseConfig.ts index f1395ba13c7..9d76951f59c 100644 --- a/src/firebaseConfig.ts +++ b/src/firebaseConfig.ts @@ -234,6 +234,10 @@ export type EmulatorsConfig = { export type ExtensionsConfig = Record; export type FirebaseConfig = { + /** + * @TJS-format uri + */ + $schema?: string; database?: DatabaseConfig; firestore?: FirestoreConfig; functions?: FunctionsConfig; From 55e894967130f26fa0c4291923ae5684481a33a8 Mon Sep 17 00:00:00 2001 From: blidd-google <112491344+blidd-google@users.noreply.github.com> Date: Wed, 28 Jun 2023 16:57:24 -0400 Subject: [PATCH 100/320] Run lifecycle hooks for specific functions (#6023) * run lifecycle hooks for individual functions --- CHANGELOG.md | 1 + src/deploy/lifecycleHooks.ts | 40 ++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 026e7b69d48..17e42f7b39d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Run lifecycle hooks for specific functions. (#6023) - Increased extension instance create poll timeout to 1h to match backend (#5969). - Refactored `ext:install` to use the latest extension metadata. (#5997) - Added descriptive error when repo is private or not found during `ext:dev:upload`. (#6052) diff --git a/src/deploy/lifecycleHooks.ts b/src/deploy/lifecycleHooks.ts index 08851844a25..008fa584657 100644 --- a/src/deploy/lifecycleHooks.ts +++ b/src/deploy/lifecycleHooks.ts @@ -132,18 +132,46 @@ function getReleventConfigs(target: string, options: Options) { onlyTargets = onlyTargets .filter((individualOnly) => { - return individualOnly.indexOf(`${target}:`) === 0; + return individualOnly.startsWith(`${target}:`); }) .map((individualOnly) => { return individualOnly.replace(`${target}:`, ""); }); - return targetConfigs.filter((config: any) => { - if (target === "functions") { - return onlyTargets.includes(config.codebase); + if (target === "functions") { + let onlyConfigs = []; + const matched = onlyTargets.reduce( + (matched: object, target: string) => ({ ...matched, [target]: false }), + {} + ); + for (const config of targetConfigs) { + if (!config.codebase) { + onlyConfigs.push(config); + } else { + const found = onlyTargets.find( + (individualOnly) => config.codebase === individualOnly.split(":")[0] + ); + if (found) { + onlyConfigs.push(config); + matched[found] = true; + } + } } - return !config.target || onlyTargets.includes(config.target); - }); + // if there are --only targets that failed to match, we assume that the target is a + // individually specified function and so we run lifecycle hooks for all codebases. + // However, this also means that codebases or functions that don't exist will also run + // the all codebase lifecycle hooks. Until we can significantly refactor the way we + // identify which functions are in which codebase in the predeploy phase, we have to live + // with this default behavior. + if (!Object.values(matched).every((matched) => matched)) { + onlyConfigs = targetConfigs; + } + return onlyConfigs; + } else { + return targetConfigs.filter((config: any) => { + return !config.target || onlyTargets.includes(config.target); + }); + } } export function lifecycleHooks( From 998a5330c9605e3248696b8398a651c44cc5fca1 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Wed, 28 Jun 2023 21:22:27 +0000 Subject: [PATCH 101/320] 12.4.2 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 6a9fdbca629..1e9c7e9c395 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.4.1", + "version": "12.4.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.4.1", + "version": "12.4.2", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index c9334a89044..39244402cda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.4.1", + "version": "12.4.2", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From c131e4fd6ba44a4b638295c3720b2bcd055d6948 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Wed, 28 Jun 2023 21:22:40 +0000 Subject: [PATCH 102/320] [firebase-release] Removed change log and reset repo after 12.4.2 release --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17e42f7b39d..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +0,0 @@ -- Run lifecycle hooks for specific functions. (#6023) -- Increased extension instance create poll timeout to 1h to match backend (#5969). -- Refactored `ext:install` to use the latest extension metadata. (#5997) -- Added descriptive error when repo is private or not found during `ext:dev:upload`. (#6052) -- Fixed issue where missing trigger warnings would be wrongly displayed when emulating extensions with HTTPS triggers. (#6055) -- Normalized extension root path before usage in `ext:dev:upload`. (#6054) From c0a59a59ca9230a98713553a1c0335d6957be154 Mon Sep 17 00:00:00 2001 From: Sairam Sakhamuri Date: Wed, 28 Jun 2023 15:52:50 -0700 Subject: [PATCH 103/320] Integrate discovery with composer (#6042) * Added runtime command discovery * Resolved comments * Added error case to analyse codebase method * Updated install command * Reorganized tests and removed unwated promise.resolve stmt * Added review changes on install command and node version string array * Changes to node.ts to include additional condions on run script * Added code comments to types * Integrate discovery with composer * Minor modification * Minor changes * Minor changes * Resolved code commits * Added undefied to return if no cmd * Added undefied to return if no cmd * Added frameworkhook interface * code comments * format error msg * format error msg * format error msg * format error msg * Code comments * Fixed imports and compose command * Fix bugs. * Update base image for node runtime. * bug fix * bug fix * Remove hooks --------- Co-authored-by: Daniel Young Lee --- .../internaltesting-frameworks-compose.ts | 6 +- src/frameworks/compose/discover/filesystem.ts | 2 +- src/frameworks/compose/discover/index.ts | 59 ++++++++++++------- .../compose/discover/runtime/node.ts | 7 +-- src/frameworks/compose/discover/types.ts | 17 ++++++ src/frameworks/compose/driver/docker.ts | 33 ++++++----- src/frameworks/compose/driver/index.ts | 5 +- src/frameworks/compose/driver/local.ts | 17 ++++-- src/frameworks/compose/index.ts | 21 ++++--- src/frameworks/compose/interfaces.ts | 16 +---- .../compose/discover/runtime/node.spec.ts | 4 +- 11 files changed, 113 insertions(+), 74 deletions(-) diff --git a/src/commands/internaltesting-frameworks-compose.ts b/src/commands/internaltesting-frameworks-compose.ts index ee85ec27d8a..a2731ef2a7e 100644 --- a/src/commands/internaltesting-frameworks-compose.ts +++ b/src/commands/internaltesting-frameworks-compose.ts @@ -4,18 +4,20 @@ import { logger } from "../logger"; import { Mode, SUPPORTED_MODES } from "../frameworks/compose/driver"; import { compose } from "../frameworks/compose"; import { FirebaseError } from "../error"; +import { LocalFileSystem } from "../frameworks/compose/discover/filesystem"; +import { frameworkSpecs } from "../frameworks/compose/discover/frameworkSpec"; export const command = new Command("internaltesting:frameworks:compose") .option("-m, --mode ", "Composer mode (local or docker)", "local") .description("compose framework in current directory") - .action((options: Options) => { + .action(async (options: Options) => { const mode = options.mode as string; if (!(SUPPORTED_MODES as unknown as string[]).includes(mode)) { throw new FirebaseError( `Unsupported mode ${mode}. Supported modes are [${SUPPORTED_MODES.join(", ")}]` ); } - const bundle = compose(mode as Mode); + const bundle = await compose(mode as Mode, new LocalFileSystem("."), frameworkSpecs); logger.info(JSON.stringify(bundle, null, 2)); return {}; }); diff --git a/src/frameworks/compose/discover/filesystem.ts b/src/frameworks/compose/discover/filesystem.ts index b2c7b7f9b47..f1e7aa513d0 100644 --- a/src/frameworks/compose/discover/filesystem.ts +++ b/src/frameworks/compose/discover/filesystem.ts @@ -2,7 +2,7 @@ import { FileSystem } from "./types"; import { pathExists, readFile } from "fs-extra"; import * as path from "path"; import { FirebaseError } from "../../../error"; -import { logger } from "../../../../src/logger"; +import { logger } from "../../../logger"; /** * Find files or read file contents present in the directory. diff --git a/src/frameworks/compose/discover/index.ts b/src/frameworks/compose/discover/index.ts index 8d3c8542ab3..43a7ba72e80 100644 --- a/src/frameworks/compose/discover/index.ts +++ b/src/frameworks/compose/discover/index.ts @@ -1,28 +1,43 @@ -import { AppSpec } from "../interfaces"; +import { Runtime, FileSystem, FrameworkSpec, RuntimeSpec } from "./types"; +import { NodejsRuntime } from "./runtime/node"; +import { FirebaseError } from "../../../error"; + +const supportedRuntimes: Runtime[] = [new NodejsRuntime()]; /** - * Discover framework in the given project directory + * Discover the best matching runtime specs for the application. */ -export function discover(): AppSpec { - return { - baseImage: "us-docker.pkg.dev/firestack-build/test/run:latest", - environmentVariables: { - NODE_ENV: "PRODUCTION", - }, - installCommand: "npm install", - buildCommand: "npm run build", - startCommand: "npm run start", +export async function discover( + fs: FileSystem, + allFrameworkSpecs: FrameworkSpec[] +): Promise { + try { + let discoveredRuntime = undefined; + for (const runtime of supportedRuntimes) { + if (await runtime.match(fs)) { + if (!discoveredRuntime) { + discoveredRuntime = runtime; + } else { + throw new FirebaseError( + `Conflit occurred as multiple runtimes ${discoveredRuntime.getRuntimeName()}, ${runtime.getRuntimeName()} are discovered in the application.` + ); + } + } + } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - afterInstall: (b) => { - console.log("HOOK: AFTER INSTALL"); - return { ...b, version: "v1alpha", notes: "afterInstall" }; - }, + if (!discoveredRuntime) { + throw new FirebaseError( + `Unable to determine the specific runtime for the application. The supported runtime options include ${supportedRuntimes + .map((x) => x.getRuntimeName()) + .join(" , ")}.` + ); + } + const runtimeSpec = await discoveredRuntime.analyseCodebase(fs, allFrameworkSpecs); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - afterBuild(b) { - console.log("HOOK: AFTER BUILD"); - return { ...b, version: "v1alpha", notes: "afterBuild" }; - }, - }; + return runtimeSpec; + } catch (error: any) { + throw new FirebaseError( + `Failed to identify required specifications to execute the application: ${error}` + ); + } } diff --git a/src/frameworks/compose/discover/runtime/node.ts b/src/frameworks/compose/discover/runtime/node.ts index 976657deac9..58a6e94fdc5 100644 --- a/src/frameworks/compose/discover/runtime/node.ts +++ b/src/frameworks/compose/discover/runtime/node.ts @@ -5,7 +5,7 @@ import { frameworkMatcher } from "../frameworkMatcher"; import { LifecycleCommands } from "../types"; import { Command } from "../types"; import { FirebaseError } from "../../../../error"; -import { logger } from "../../../../../src/logger"; +import { logger } from "../../../../logger"; import { conjoinOptions } from "../../../utils"; export interface PackageJSON { @@ -23,7 +23,6 @@ const YARN_LOCK = "yarn.lock"; export class NodejsRuntime implements Runtime { private readonly runtimeRequiredFiles: string[] = [PACKAGE_JSON]; - private readonly contentCache: Record = {}; // Checks if the codebase is using Node as runtime. async match(fs: FileSystem): Promise { @@ -41,7 +40,7 @@ export class NodejsRuntime implements Runtime { getNodeImage(engine: Record | undefined): string { // If no version is mentioned explicitly, assuming application is compatible with latest version. if (!engine || !engine.node) { - return `node:${supportedNodeVersions[supportedNodeVersions.length - 1]}-slim`; + return "us-docker.pkg.dev/firestack-build/test/run"; } const versionNumber = engine.node; @@ -54,7 +53,7 @@ export class NodejsRuntime implements Runtime { ); } - return `node:${versionNumber}-slim`; + return "us-docker.pkg.dev/firestack-build/test/run"; } async getPackageManager(fs: FileSystem): Promise { diff --git a/src/frameworks/compose/discover/types.ts b/src/frameworks/compose/discover/types.ts index b919e552c4b..a89fb00c312 100644 --- a/src/frameworks/compose/discover/types.ts +++ b/src/frameworks/compose/discover/types.ts @@ -1,3 +1,5 @@ +import { AppBundle } from "../interfaces"; + export interface FileSystem { exists(file: string): Promise; read(file: string): Promise; @@ -77,4 +79,19 @@ export interface RuntimeSpec { // The runtime has detected a command that should always be run irrespective of // the framework (e.g. the "build" script always wins in Node) detectedCommands?: LifecycleCommands; + + environmentVariables?: Record; + + // Framework authors can execute framework-specific code using hooks at different stages of Frameworks API build process. + frameworkHooks?: FrameworkHooks; +} + +export interface FrameworkHooks { + // Programmatic hook with access to filesystem and nodejs API to inspect the workspace. + // Primarily intended to gather hints relevant to the build. + afterInstall?: (b: AppBundle) => AppBundle; + + // Programmatic hook with access to filesystem and nodejs API to inspect the build artifacts. + // Primarily intended to informs what assets should be deployed. + afterBuild?: (b: AppBundle) => AppBundle; } diff --git a/src/frameworks/compose/driver/docker.ts b/src/frameworks/compose/driver/docker.ts index 70d9d4344b9..8033d7c16cd 100644 --- a/src/frameworks/compose/driver/docker.ts +++ b/src/frameworks/compose/driver/docker.ts @@ -2,8 +2,9 @@ import * as fs from "node:fs"; import * as path from "node:path"; import * as spawn from "cross-spawn"; -import { AppBundle, AppSpec, Driver, Hook } from "../interfaces"; +import { AppBundle, Driver, Hook } from "../interfaces"; import { BUNDLE_PATH, genHookScript } from "./hooks"; +import { RuntimeSpec } from "../discover/types"; const ADAPTER_SCRIPTS_PATH = "./.firebase/adapters" as const; @@ -98,7 +99,7 @@ export class DockerfileBuilder { export class DockerDriver implements Driver { private dockerfileBuilder; - constructor(readonly spec: AppSpec) { + constructor(readonly spec: RuntimeSpec) { this.dockerfileBuilder = new DockerfileBuilder(); this.dockerfileBuilder.from(spec.baseImage, "base").user("firebase"); } @@ -148,21 +149,25 @@ export class DockerDriver implements Driver { } install(): void { - this.dockerfileBuilder - .fromLastStage(DOCKER_STAGE_INSTALL) - .workdir("/home/firebase/app") - .envs(this.spec.environmentVariables || {}) - .copyForFirebase("package.json", ".") - .run(this.spec.installCommand); - this.buildStage(DOCKER_STAGE_INSTALL, "."); + if (this.spec.installCommand) { + this.dockerfileBuilder + .fromLastStage(DOCKER_STAGE_INSTALL) + .workdir("/home/firebase/app") + .envs(this.spec.environmentVariables || {}) + .copyForFirebase("package.json", ".") + .run(this.spec.installCommand); + this.buildStage(DOCKER_STAGE_INSTALL, "."); + } } build(): void { - this.dockerfileBuilder - .fromLastStage(DOCKER_STAGE_BUILD) - .copyForFirebase(".", ".") - .run(this.spec.buildCommand); - this.buildStage(DOCKER_STAGE_BUILD, "."); + if (this.spec.detectedCommands?.build) { + this.dockerfileBuilder + .fromLastStage(DOCKER_STAGE_BUILD) + .copyForFirebase(".", ".") + .run(this.spec.detectedCommands.build.cmd); + this.buildStage(DOCKER_STAGE_BUILD, "."); + } } export(bundle: AppBundle): void { diff --git a/src/frameworks/compose/driver/index.ts b/src/frameworks/compose/driver/index.ts index 8adc6480708..1779fdb5c3e 100644 --- a/src/frameworks/compose/driver/index.ts +++ b/src/frameworks/compose/driver/index.ts @@ -1,6 +1,7 @@ -import { AppSpec, Driver } from "../interfaces"; +import { Driver } from "../interfaces"; import { LocalDriver } from "./local"; import { DockerDriver } from "./docker"; +import { RuntimeSpec } from "../discover/types"; export const SUPPORTED_MODES = ["local", "docker"] as const; export type Mode = (typeof SUPPORTED_MODES)[number]; @@ -8,7 +9,7 @@ export type Mode = (typeof SUPPORTED_MODES)[number]; /** * Returns the driver that provides the execution context for the composer. */ -export function getDriver(mode: Mode, app: AppSpec): Driver { +export function getDriver(mode: Mode, app: RuntimeSpec): Driver { if (mode === "local") { return new LocalDriver(app); } else if (mode === "docker") { diff --git a/src/frameworks/compose/driver/local.ts b/src/frameworks/compose/driver/local.ts index da23187bf58..5bd219c113c 100644 --- a/src/frameworks/compose/driver/local.ts +++ b/src/frameworks/compose/driver/local.ts @@ -1,11 +1,12 @@ import * as fs from "node:fs"; import * as spawn from "cross-spawn"; -import { AppBundle, AppSpec, Hook, Driver } from "../interfaces"; +import { AppBundle, Hook, Driver } from "../interfaces"; import { BUNDLE_PATH, genHookScript } from "./hooks"; +import { RuntimeSpec } from "../discover/types"; export class LocalDriver implements Driver { - constructor(readonly spec: AppSpec) {} + constructor(readonly spec: RuntimeSpec) {} private execCmd(cmd: string, args: string[]) { const ret = spawn.sync(cmd, args, { @@ -18,13 +19,17 @@ export class LocalDriver implements Driver { } install(): void { - const [cmd, ...args] = this.spec.installCommand.split(" "); - this.execCmd(cmd, args); + if (this.spec.installCommand) { + const [cmd, ...args] = this.spec.installCommand.split(" "); + this.execCmd(cmd, args); + } } build(): void { - const [cmd, ...args] = this.spec.buildCommand.split(" "); - this.execCmd(cmd, args); + if (this.spec.detectedCommands?.build) { + const [cmd, ...args] = this.spec.detectedCommands.build.cmd.split(" "); + this.execCmd(cmd, args); + } } // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/src/frameworks/compose/index.ts b/src/frameworks/compose/index.ts index 24e45490be1..4a5d066ca8c 100644 --- a/src/frameworks/compose/index.ts +++ b/src/frameworks/compose/index.ts @@ -1,31 +1,36 @@ import { AppBundle } from "./interfaces"; import { getDriver, Mode } from "./driver"; import { discover } from "./discover"; +import { FrameworkSpec, FileSystem } from "./discover/types"; /** * Run composer in the specified execution context. */ -export function compose(mode: Mode): AppBundle { +export async function compose( + mode: Mode, + fs: FileSystem, + allFrameworkSpecs: FrameworkSpec[] +): Promise { let bundle: AppBundle = { version: "v1alpha" }; - const spec = discover(); + const spec = await discover(fs, allFrameworkSpecs); const driver = getDriver(mode, spec); - if (spec.startCommand) { + if (spec.detectedCommands?.run) { bundle.server = { start: { - cmd: spec.startCommand.split(" "), + cmd: spec.detectedCommands.run.cmd.split(" "), }, }; } driver.install(); - if (spec.afterInstall) { - bundle = driver.execHook(bundle, spec.afterInstall); + if (spec.frameworkHooks?.afterInstall) { + bundle = driver.execHook(bundle, spec.frameworkHooks.afterInstall); } driver.build(); - if (spec.afterBuild) { - bundle = driver.execHook(bundle, spec.afterBuild); + if (spec.frameworkHooks?.afterBuild) { + bundle = driver.execHook(bundle, spec.frameworkHooks?.afterBuild); } if (bundle.server) { diff --git a/src/frameworks/compose/interfaces.ts b/src/frameworks/compose/interfaces.ts index db3caee4898..068b28a178b 100644 --- a/src/frameworks/compose/interfaces.ts +++ b/src/frameworks/compose/interfaces.ts @@ -1,3 +1,5 @@ +import { RuntimeSpec } from "./discover/types"; + export interface AppBundle { version: "v1alpha"; server?: ServerConfig; @@ -22,22 +24,10 @@ interface StartConfig { runtime?: "nodejs18" | string; } -export interface AppSpec { - baseImage: string; - packageManagerInstallCommand?: string; - environmentVariables?: Record; - installCommand: string; - buildCommand: string; - startCommand: string; - - afterInstall?: (b: AppBundle) => AppBundle; - afterBuild?: (b: AppBundle) => AppBundle; -} - export type Hook = (b: AppBundle) => AppBundle; export class Driver { - constructor(readonly spec: AppSpec) {} + constructor(readonly spec: RuntimeSpec) {} install(): void { throw new Error("install() not implemented"); diff --git a/src/test/frameworks/compose/discover/runtime/node.spec.ts b/src/test/frameworks/compose/discover/runtime/node.spec.ts index b2bbaee767c..4dedc70db6a 100644 --- a/src/test/frameworks/compose/discover/runtime/node.spec.ts +++ b/src/test/frameworks/compose/discover/runtime/node.spec.ts @@ -41,7 +41,7 @@ describe("NodejsRuntime", () => { node: "18", }; const actualImage = nodeJSRuntime.getNodeImage(version); - const expectedImage = "node:18-slim"; + const expectedImage = "us-docker.pkg.dev/firestack-build/test/run"; expect(actualImage).to.deep.equal(expectedImage); }); @@ -189,7 +189,7 @@ describe("NodejsRuntime", () => { const actual = await nodeJSRuntime.analyseCodebase(fileSystem, allFrameworks); const expected = { id: "nodejs", - baseImage: "node:18-slim", + baseImage: "us-docker.pkg.dev/firestack-build/test/run", packageManagerInstallCommand: undefined, installCommand: "npm install", detectedCommands: { From 9f14838ee831db8f8642e56b5fc1194bbbc1c73d Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 29 Jun 2023 11:52:05 -0700 Subject: [PATCH 104/320] VSCode plugin: Workarounds for functions code + Monospace settings (#6056) --- firebase-vscode/package-lock.json | 4 +-- firebase-vscode/package.json | 15 ++++++---- firebase-vscode/scripts/swap-pkg.js | 22 ++++++++++++-- firebase-vscode/webpack.common.js | 46 +++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 10 deletions(-) diff --git a/firebase-vscode/package-lock.json b/firebase-vscode/package-lock.json index 56f8dbfade9..ef2240a2da3 100644 --- a/firebase-vscode/package-lock.json +++ b/firebase-vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "firebase-vscode", - "version": "0.0.22-alpha.0", + "version": "0.0.23-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-vscode", - "version": "0.0.22-alpha.0", + "version": "0.0.23-alpha.1", "dependencies": { "@vscode/codicons": "0.0.30", "@vscode/webview-ui-toolkit": "^1.2.1", diff --git a/firebase-vscode/package.json b/firebase-vscode/package.json index 415cf731ecb..1eae05edc62 100644 --- a/firebase-vscode/package.json +++ b/firebase-vscode/package.json @@ -3,7 +3,7 @@ "displayName": "firebase-vscode", "publisher": "firebase", "description": "VSCode Extension for Firebase", - "version": "0.0.22-alpha.0", + "version": "0.0.23-alpha.1", "engines": { "vscode": "^1.69.0" }, @@ -22,12 +22,12 @@ "properties": { "firebase.debug": { "type": "boolean", - "default": false, + "default": true, "description": "Enable writing debug-level messages to the file provided in firebase.debugLogPath (requires restart)" }, "firebase.debugLogPath": { "type": "string", - "default": "", + "default": "/tmp/firebase-plugin.log", "description": "If firebase.debug is true, appends debug-level messages to the provided file (requires restart)" }, "firebase.npmPath": { @@ -37,8 +37,8 @@ }, "firebase.useFrameworks": { "type": "boolean", - "default": false, - "description": "Enable web frameworks in a local VSCode environment" + "default": true, + "description": "Enable web frameworks" } } }, @@ -133,5 +133,8 @@ "webpack": "^5.75.0", "webpack-cli": "^5.0.1", "webpack-merge": "^5.8.0" - } + }, + "extensionDependencies": [ + "google.monospace" + ] } \ No newline at end of file diff --git a/firebase-vscode/scripts/swap-pkg.js b/firebase-vscode/scripts/swap-pkg.js index f8655afa9b3..92f68fce843 100644 --- a/firebase-vscode/scripts/swap-pkg.js +++ b/firebase-vscode/scripts/swap-pkg.js @@ -2,6 +2,13 @@ const { writeFileSync } = require("fs"); const path = require("path"); const pkg = require(path.join(__dirname, "../package.json")); +// Swaps package.json config as appropriate for packaging for +// Monospace or VSCE marketplace. + +// TODO(chholland): Don't overwrite the real package.json file and +// create a generated one in dist/ - redo .vscodeignore to package +// dist/ + let target = "vsce"; process.argv.forEach((arg) => { @@ -13,12 +20,23 @@ process.argv.forEach((arg) => { if (target === "vsce") { delete pkg.extensionDependencies; console.log( - "Removing google.monospace extensionDependency for VSCE" + " packaging." + "Removing google.monospace extensionDependency for VSCE packaging." + ); + pkg.contributes.configuration.properties['firebase.debug'].default = false; + pkg.contributes.configuration.properties['firebase.debugLogPath'].default = ""; + console.log( + "Setting default debug log settings to off for VSCE packaging." ); } else if (target === "monospace") { pkg.extensionDependencies = ["google.monospace"]; console.log( - "Adding google.monospace extensionDependency for Monospace" + " packaging." + "Adding google.monospace extensionDependency for Monospace packaging." + ); + pkg.contributes.configuration.properties['firebase.debug'].default = true; + pkg.contributes.configuration.properties['firebase.debugLogPath'].default = + "/tmp/firebase-plugin.log"; + console.log( + "Setting default debug log settings to on for Monospace packaging." ); } diff --git a/firebase-vscode/webpack.common.js b/firebase-vscode/webpack.common.js index ca1e75761e2..d23b42fa85d 100644 --- a/firebase-vscode/webpack.common.js +++ b/firebase-vscode/webpack.common.js @@ -65,22 +65,61 @@ const extensionConfig = { loader: "string-replace-loader", options: { multiple: [ + // CLI code has absolute path to templates/. We copy templates/ + // into dist, and this is the correct path now. { search: /(\.|\.\.)[\.\/]+templates/g, replace: "./templates", }, + // CLI code has absolute path to schema/. We copy schema/ + // into dist, and this is the correct path now. { search: /(\.|\.\.)[\.\/]+schema/g, replace: "./schema", }, + // Without doing this, it dynamically grabs pkg.name from + // package.json, which is the firebase-vscode package name. + // We want to use the same configstore name as firebase-tools + // so the CLI and extension can share login state. { search: /Configstore\(pkg\.name\)/g, replace: "Configstore('firebase-tools')", }, // TODO(hsubox76): replace with something more robust + // This is an issue with a local call to cross-env-shell.js + // and a dependency on calling the Node executable using an env + // variable which returns a string with a lot of unusual characters + // if called inside VSCode. + // We may be able to copy cross-env-shell.js into dist? + // For the node executable we can probably just call Node, still + // need to search/replace though { search: "childProcess.spawn(translatedCommand", replace: "childProcess.spawn(escapedCommand" + }, + // Some CLI code uses module.exports for test stubbing. + // We are using ES2020 and it doesn't recognize functions called + // as exports.functionName() or module.exports.functionName(). + // Maybe separate those CLI src files at a future time so they can + // still be stubbed for tests without doing this, but this is + // a temporary fix. + { + search: /module\.exports\.([a-zA-Z0-9]+)\(/g, + replace: (match) => match.replace('module.exports.', '') + }, + // cloudtasks.ts type casts so there's an " as [type]" before the + // starting paren to call the function + { + search: /module\.exports\.([a-zA-Z0-9]+) as/g, + replace: (match) => match.replace('module.exports.', '') + }, + // Disallow starting . to ensure it doesn't conflict with + // module.exports + // Must end with a paren to avoid overwriting exports assignments + // such as "exports.something = value" + { + search: /[^\.]exports\.([a-zA-Z0-9]+)\(/g, + replace: (match) => match.replace('exports.', '') } ], }, @@ -97,6 +136,13 @@ const extensionConfig = { { from: "../schema", to: "./schema", + }, + // Copy uncompiled JS files called at runtime by + // firebase-tools/src/parseTriggers.ts + { + from: "*.js", + to: './', + context: "../src/deploy/functions/runtimes/node", } ], }) From 57dd7fef80d9b9294da41bb93cf25a1108674459 Mon Sep 17 00:00:00 2001 From: Sairam Sakhamuri Date: Thu, 29 Jun 2023 15:03:30 -0700 Subject: [PATCH 105/320] Git to cloud build (#6044) * Initial commit integrate init with api * Revert "Initial commit integrate init with api" This reverts commit 14751512d769d675e9d9fc624c34dfe41f461f0e. * removed internaltesting:frameworks:int command * integrate git repo with cloudBuildRepo * Added changes to create stack * Added changes to create stack * Added code to omit output fields in Stack * Added poller operation * Added poller operation * Added code to integrate init flow to link Git repo and to call frameworks api * Minor changes * minor changes * deleted output file * Rearranged files * Fix imports * Reorganized files * minor changes --- src/commands/index.ts | 2 - .../internaltesting-frameworks-init.ts | 14 ----- src/{api => gcp}/frameworks.ts | 24 ++++---- src/init/features/frameworks/index.ts | 53 ++++++++++++++++ .../features/{composer => frameworks}/repo.ts | 6 +- src/test/init/frameworks/index.spec.ts | 61 +++++++++++++++++++ .../repo.spec.ts} | 2 +- 7 files changed, 129 insertions(+), 33 deletions(-) delete mode 100644 src/commands/internaltesting-frameworks-init.ts rename src/{api => gcp}/frameworks.ts (84%) rename src/init/features/{composer => frameworks}/repo.ts (97%) create mode 100644 src/test/init/frameworks/index.spec.ts rename src/test/init/{features/composer.spec.ts => frameworks/repo.spec.ts} (98%) diff --git a/src/commands/index.ts b/src/commands/index.ts index b3fa211894e..1b3c5d3bc30 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -150,8 +150,6 @@ export function load(client: any): any { client.internaltesting.frameworks.compose = loadCommand("internaltesting-frameworks-compose"); client.internaltesting.functions = {}; client.internaltesting.functions.discover = loadCommand("internaltesting-functions-discover"); - client.internaltesting.frameworks = {}; - client.internaltesting.frameworks.init = loadCommand("internaltesting-frameworks-init"); } client.login = loadCommand("login"); client.login.add = loadCommand("login-add"); diff --git a/src/commands/internaltesting-frameworks-init.ts b/src/commands/internaltesting-frameworks-init.ts deleted file mode 100644 index 729fde0e9d9..00000000000 --- a/src/commands/internaltesting-frameworks-init.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Command } from "../command"; -import { linkGitHubRepository } from "../init/features/composer/repo"; -import { Options } from "../options"; -import { needProjectId } from "../projectUtils"; -import requireInteractive from "../requireInteractive"; - -export const command = new Command("internaltesting:frameworks:init") - .description("connect github repo to cloud build") - .before(requireInteractive) - .action(async (options: Options) => { - const projectId = needProjectId(options); - await linkGitHubRepository(projectId, "us-central2", "stack0"); - // TODO: send repo metadata to control plane - }); diff --git a/src/api/frameworks.ts b/src/gcp/frameworks.ts similarity index 84% rename from src/api/frameworks.ts rename to src/gcp/frameworks.ts index 30fcc41bd66..b74b8dbff20 100644 --- a/src/api/frameworks.ts +++ b/src/gcp/frameworks.ts @@ -1,7 +1,7 @@ import { Client } from "../apiv2"; import { frameworksOrigin } from "../api"; -export const API_VERSION = "v1"; +export const API_VERSION = "v2"; const client = new Client({ urlPrefix: frameworksOrigin, @@ -9,7 +9,7 @@ const client = new Client({ apiVersion: API_VERSION, }); -export type State = "BUILDING" | "BUILD" | "DEPLOYING" | "READY" | "FAILED"; +type State = "BUILDING" | "BUILD" | "DEPLOYING" | "READY" | "FAILED"; interface Codebase { repository?: string; @@ -17,7 +17,7 @@ interface Codebase { } /** A Stack, the primary resource of Frameworks. */ -interface Stack { +export interface Stack { name: string; mode?: string; codebase: Codebase; @@ -29,7 +29,7 @@ interface Stack { export type StackOutputOnlyFields = "createTime" | "updateTime" | "uri"; -interface Build { +export interface Build { name: string; state: State; error: Status; @@ -61,7 +61,7 @@ interface CodebaseSource { // end oneof reference } -export interface OperationMetadata { +interface OperationMetadata { createTime: string; endTime: string; target: string; @@ -87,14 +87,15 @@ export interface Operation { export async function createStack( projectId: string, location: string, - stackId: string, - stack: Stack + stackInput: Omit ): Promise { + const stackId = stackInput.name; const res = await client.post, Operation>( `projects/${projectId}/locations/${location}/stacks`, - stack, + stackInput, { queryParams: { stackId } } ); + return res.body; } @@ -105,13 +106,14 @@ export async function createBuild( projectId: string, location: string, stackId: string, - buildId: string, - build: Build + buildInput: Omit ): Promise { + const buildId = buildInput.name; const res = await client.post, Operation>( `projects/${projectId}/locations/${location}/stacks/${stackId}/builds`, - build, + buildInput, { queryParams: { buildId } } ); + return res.body; } diff --git a/src/init/features/frameworks/index.ts b/src/init/features/frameworks/index.ts index 8b75e5023c9..e26b126b2dd 100644 --- a/src/init/features/frameworks/index.ts +++ b/src/init/features/frameworks/index.ts @@ -8,11 +8,26 @@ import { DEFAULT_DEPLOY_METHOD, ALLOWED_DEPLOY_METHODS, } from "./constants"; +import { linkGitHubRepository } from "./repo"; +import { Stack, StackOutputOnlyFields } from "../../../gcp/frameworks"; +import { Repository } from "../../../gcp/cloudbuild"; +import * as poller from "../../../operation-poller"; +import { frameworksOrigin } from "../../../api"; +import * as gcp from "../../../gcp/frameworks"; +import { API_VERSION } from "../../../gcp/frameworks"; + +const frameworksPollerOptions: Omit = { + apiOrigin: frameworksOrigin, + apiVersion: API_VERSION, + masterTimeout: 25 * 60 * 1_000, + maxBackoff: 10_000, +}; /** * Setup new frameworks project. */ export async function doSetup(setup: any): Promise { + const projectId: string = setup?.rcfile?.projects?.default; setup.frameworks = {}; utils.logBullet("First we need a few details to create your service."); @@ -54,4 +69,42 @@ export async function doSetup(setup: any): Promise { }, setup.frameworks ); + + if (setup.frameworks.deployMethod === "github") { + const cloudBuildConnRepo = await linkGitHubRepository( + projectId, + setup.frameworks.region, + setup.frameworks.serviceName + ); + toStack(cloudBuildConnRepo, setup.frameworks.serviceName); + } +} + +function toStack( + cloudBuildConnRepo: Repository, + stackId: string +): Omit { + return { + name: stackId, + codebase: { repository: cloudBuildConnRepo.name, rootDirectory: "/" }, + labels: {}, + }; +} + +/** + * Creates Stack object from long running operations. + */ +export async function createStack( + projectId: string, + location: string, + stackInput: Omit +): Promise { + const op = await gcp.createStack(projectId, location, stackInput); + const stack = await poller.pollOperation({ + ...frameworksPollerOptions, + pollerName: `create-${projectId}-${location}-${stackInput.name}`, + operationResourceName: op.name, + }); + + return stack; } diff --git a/src/init/features/composer/repo.ts b/src/init/features/frameworks/repo.ts similarity index 97% rename from src/init/features/composer/repo.ts rename to src/init/features/frameworks/repo.ts index c5080ffa73f..5b726b855f5 100644 --- a/src/init/features/composer/repo.ts +++ b/src/init/features/frameworks/repo.ts @@ -25,10 +25,6 @@ function extractRepoSlugFromURI(remoteUri: string): string | undefined { return match[1]; } -function generateConnectionId(stackId: string): string { - return `composer-${stackId}-conn`; -} - /** * Generates a repository ID. * N.B. The deterministic nature of the repository ID implies that each @@ -48,7 +44,7 @@ export async function linkGitHubRepository( location: string, stackId: string ): Promise { - const connectionId = generateConnectionId(stackId); + const connectionId = stackId; await getOrCreateConnection(projectId, location, connectionId); let remoteUri = await promptRepositoryURI(projectId, location, connectionId); diff --git a/src/test/init/frameworks/index.spec.ts b/src/test/init/frameworks/index.spec.ts new file mode 100644 index 00000000000..1534f014f55 --- /dev/null +++ b/src/test/init/frameworks/index.spec.ts @@ -0,0 +1,61 @@ +import * as sinon from "sinon"; +import { expect } from "chai"; + +import * as gcp from "../../../gcp/frameworks"; +import * as poller from "../../../operation-poller"; +import { createStack } from "../../../init/features/frameworks/index"; + +describe("operationsConverter", () => { + const sandbox: sinon.SinonSandbox = sinon.createSandbox(); + + let pollOperationStub: sinon.SinonStub; + let createStackStub: sinon.SinonStub; + + beforeEach(() => { + pollOperationStub = sandbox + .stub(poller, "pollOperation") + .throws("Unexpected pollOperation call"); + createStackStub = sandbox.stub(gcp, "createStack").throws("Unexpected createStack call"); + }); + + afterEach(() => { + sandbox.verifyAndRestore(); + }); + + describe("createStack", () => { + const projectId = "projectId"; + const location = "us-central1"; + const stackId = "stackId"; + const stackInput = { + name: stackId, + codebase: { + repository: `projects/${projectId}/locations/${location}/connections/${stackId}`, + rootDirectory: "/", + }, + labels: {}, + }; + const op = { + name: `projects/${projectId}/locations/${location}/stacks/${stackId}`, + done: true, + }; + const completeStack = { + name: `projects/${projectId}/locations/${location}/stacks/${stackId}`, + codebase: { + repository: `projects/${projectId}/locations/${location}/connections/${stackId}`, + rootDirectory: "/", + }, + labels: {}, + createTime: "0", + updateTime: "1", + uri: "https://placeholder.com", + }; + + it("checks is correct arguments are sent & creates a stack", async () => { + createStackStub.resolves(op); + pollOperationStub.resolves(completeStack); + + await createStack(projectId, location, stackInput); + expect(createStackStub).to.be.calledWith(projectId, location, stackInput); + }); + }); +}); diff --git a/src/test/init/features/composer.spec.ts b/src/test/init/frameworks/repo.spec.ts similarity index 98% rename from src/test/init/features/composer.spec.ts rename to src/test/init/frameworks/repo.spec.ts index 661bdd831aa..1c21b608b43 100644 --- a/src/test/init/features/composer.spec.ts +++ b/src/test/init/frameworks/repo.spec.ts @@ -5,7 +5,7 @@ import * as gcb from "../../../gcp/cloudbuild"; import * as prompt from "../../../prompt"; import * as poller from "../../../operation-poller"; import { FirebaseError } from "../../../error"; -import * as repo from "../../../init/features/composer/repo"; +import * as repo from "../../../init/features/frameworks/repo"; import * as utils from "../../../utils"; describe("composer", () => { From e091b2af7f9c7e0120bbe673a753609d896c3a38 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Wed, 5 Jul 2023 10:12:58 -0700 Subject: [PATCH 106/320] Frameworks: Call "next build" from command line instead of import (#6066) --- firebase-vscode/package-lock.json | 4 ++-- firebase-vscode/package.json | 11 ++++------- src/frameworks/next/index.ts | 21 ++++++++++++++------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/firebase-vscode/package-lock.json b/firebase-vscode/package-lock.json index ef2240a2da3..ccbdb5e7b61 100644 --- a/firebase-vscode/package-lock.json +++ b/firebase-vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "firebase-vscode", - "version": "0.0.23-alpha.1", + "version": "0.0.23-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-vscode", - "version": "0.0.23-alpha.1", + "version": "0.0.23-alpha.2", "dependencies": { "@vscode/codicons": "0.0.30", "@vscode/webview-ui-toolkit": "^1.2.1", diff --git a/firebase-vscode/package.json b/firebase-vscode/package.json index 1eae05edc62..e18acd3939c 100644 --- a/firebase-vscode/package.json +++ b/firebase-vscode/package.json @@ -3,7 +3,7 @@ "displayName": "firebase-vscode", "publisher": "firebase", "description": "VSCode Extension for Firebase", - "version": "0.0.23-alpha.1", + "version": "0.0.23-alpha.2", "engines": { "vscode": "^1.69.0" }, @@ -22,12 +22,12 @@ "properties": { "firebase.debug": { "type": "boolean", - "default": true, + "default": false, "description": "Enable writing debug-level messages to the file provided in firebase.debugLogPath (requires restart)" }, "firebase.debugLogPath": { "type": "string", - "default": "/tmp/firebase-plugin.log", + "default": "", "description": "If firebase.debug is true, appends debug-level messages to the provided file (requires restart)" }, "firebase.npmPath": { @@ -133,8 +133,5 @@ "webpack": "^5.75.0", "webpack-cli": "^5.0.1", "webpack-merge": "^5.8.0" - }, - "extensionDependencies": [ - "google.monospace" - ] + } } \ No newline at end of file diff --git a/src/frameworks/next/index.ts b/src/frameworks/next/index.ts index e64ae4865d1..df3fb97f9de 100644 --- a/src/frameworks/next/index.ts +++ b/src/frameworks/next/index.ts @@ -28,6 +28,7 @@ import { relativeRequire, findDependency, validateLocales, + getNodeModuleBin, } from "../utils"; import { BuildResult, FrameworkType, SupportLevel } from "../interfaces"; @@ -101,8 +102,6 @@ export async function discover(dir: string) { * Build a next.js application. */ export async function build(dir: string): Promise { - const { default: nextBuild } = relativeRequire(dir, "next/dist/build"); - await warnIfCustomBuildScript(dir, name, DEFAULT_BUILD_SCRIPT); const reactVersion = getReactVersion(dir); @@ -111,12 +110,20 @@ export async function build(dir: string): Promise { process.env.__NEXT_REACT_ROOT = "true"; } - await nextBuild(dir, null, false, false, true).catch((e) => { - // Err on the side of displaying this error, since this is likely a bug in - // the developer's code that we want to display immediately - console.error(e.message); - throw e; + const cli = getNodeModuleBin("next", dir); + + const nextBuild = new Promise((resolve, reject) => { + const buildProcess = spawn(cli, ["build"], { cwd: dir }); + buildProcess.stdout?.on("data", (data) => logger.info(data.toString())); + buildProcess.stderr?.on("data", (data) => logger.info(data.toString())); + buildProcess.on("error", (err) => { + reject(new FirebaseError(`Unable to build your Next.js app: ${err}`)); + }); + buildProcess.on("exit", (code) => { + resolve(code); + }); }); + await nextBuild; const reasonsForBackend = new Set(); const { distDir, trailingSlash, basePath: baseUrl } = await getConfig(dir); From b7730e3ee9d6385c7039c0114111672601880a78 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Wed, 5 Jul 2023 15:29:33 -0700 Subject: [PATCH 107/320] Add support for running package manager install command. (#6064) --- src/frameworks/compose/driver/docker.ts | 13 ++++++++++--- src/frameworks/compose/driver/local.ts | 4 ++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/frameworks/compose/driver/docker.ts b/src/frameworks/compose/driver/docker.ts index 8033d7c16cd..4e84f16dc38 100644 --- a/src/frameworks/compose/driver/docker.ts +++ b/src/frameworks/compose/driver/docker.ts @@ -105,7 +105,11 @@ export class DockerDriver implements Driver { } private execDockerPush(args: string[]) { - console.log(`executing docker build: ${args.join(" ")}`); + console.debug(JSON.stringify({ message: `executing docker build: ${args.join(" ")}` })); + console.info( + JSON.stringify({ foo: "bar", message: `executing docker build: ${args.join(" ")}` }) + ); + console.error(JSON.stringify({ message: `executing docker build: ${args.join(" ")}` })); return spawn.sync("docker", ["push", ...args], { stdio: [/* stdin= */ "pipe", /* stdout= */ "inherit", /* stderr= */ "inherit"], }); @@ -154,8 +158,11 @@ export class DockerDriver implements Driver { .fromLastStage(DOCKER_STAGE_INSTALL) .workdir("/home/firebase/app") .envs(this.spec.environmentVariables || {}) - .copyForFirebase("package.json", ".") - .run(this.spec.installCommand); + .copyForFirebase("package.json", "."); + if (this.spec.packageManagerInstallCommand) { + this.dockerfileBuilder.run(this.spec.packageManagerInstallCommand); + } + this.dockerfileBuilder.run(this.spec.installCommand); this.buildStage(DOCKER_STAGE_INSTALL, "."); } } diff --git a/src/frameworks/compose/driver/local.ts b/src/frameworks/compose/driver/local.ts index 5bd219c113c..f20af3583bc 100644 --- a/src/frameworks/compose/driver/local.ts +++ b/src/frameworks/compose/driver/local.ts @@ -20,6 +20,10 @@ export class LocalDriver implements Driver { install(): void { if (this.spec.installCommand) { + if (this.spec.packageManagerInstallCommand) { + const [cmd, ...args] = this.spec.packageManagerInstallCommand.split(" "); + this.execCmd(cmd, args); + } const [cmd, ...args] = this.spec.installCommand.split(" "); this.execCmd(cmd, args); } From 1ef81dfec73c0b06ff22e1bb40d3cb4f51ee0674 Mon Sep 17 00:00:00 2001 From: christhompsongoogle <106194718+christhompsongoogle@users.noreply.github.com> Date: Thu, 6 Jul 2023 10:36:57 -0700 Subject: [PATCH 108/320] Release Firebase Emulator UI v 1.11.7 (#6079) * Release Firebase Emulator Ui v 1.11.7 * Update commit --------- Co-authored-by: joehan --- CHANGELOG.md | 1 + src/emulator/downloadableEmulators.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..5b951c3337e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Released Firebase Emulator UI v1.11.7, which includes preview support for multiple Firestore databases (#6079) diff --git a/src/emulator/downloadableEmulators.ts b/src/emulator/downloadableEmulators.ts index ca3ec53dbe8..32de1c709ce 100644 --- a/src/emulator/downloadableEmulators.ts +++ b/src/emulator/downloadableEmulators.ts @@ -45,9 +45,9 @@ const EMULATOR_UPDATE_DETAILS: { [s in DownloadableEmulators]: EmulatorUpdateDet ui: experiments.isEnabled("emulatoruisnapshot") ? { version: "SNAPSHOT", expectedSize: -1, expectedChecksum: "" } : { - version: "1.11.6", - expectedSize: 3063444, - expectedChecksum: "14b971f4ed4909f348e647db7114d62b", + version: "1.11.7", + expectedSize: 3064105, + expectedChecksum: "bd2bcc331cbf613a5b3b55a1ce08998b", }, pubsub: { version: "0.7.1", From 794b869330efa8b4bbd08b0c53754c3d132f3046 Mon Sep 17 00:00:00 2001 From: aalej Date: Fri, 7 Jul 2023 02:03:47 +0800 Subject: [PATCH 109/320] Update firebase open links (#6073) * Update firebase open links * adding changelog --------- Co-authored-by: joehan --- CHANGELOG.md | 3 ++- src/commands/open.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b951c3337e..07dd3b508f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ -- Released Firebase Emulator UI v1.11.7, which includes preview support for multiple Firestore databases (#6079) +- Fixed incorrect links in `firebase open hosting` and `firebase open crash`. (#6073) +- Released Firebase Emulator UI v1.11.7, which includes preview support for multiple Firestore databases. (#6079) diff --git a/src/commands/open.ts b/src/commands/open.ts index 45d5a5138c0..3b30b334364 100644 --- a/src/commands/open.ts +++ b/src/commands/open.ts @@ -22,7 +22,7 @@ const LINKS: Link[] = [ { name: "Analytics", arg: "analytics", consolePath: "/analytics" }, { name: "Authentication: Providers", arg: "auth", consolePath: "/authentication/providers" }, { name: "Authentication: Users", arg: "auth:users", consolePath: "/authentication/users" }, - { name: "Crash Reporting", arg: "crash", consolePath: "/monitoring" }, + { name: "Crash Reporting", arg: "crash", consolePath: "/crashlytics" }, { name: "Database: Data", arg: "database", consolePath: "/database/data" }, { name: "Database: Rules", arg: "database:rules", consolePath: "/database/rules" }, { name: "Docs", arg: "docs", url: "https://firebase.google.com/docs" }, @@ -44,7 +44,7 @@ const LINKS: Link[] = [ { name: "Functions", arg: "functions", consolePath: "/functions/list" }, { name: "Functions Log", arg: "functions:log" } /* Special Case */, { name: "Hosting: Deployed Site", arg: "hosting:site" } /* Special Case */, - { name: "Hosting", arg: "hosting", consolePath: "/hosting/main" }, + { name: "Hosting", arg: "hosting", consolePath: "/hosting/sites" }, { name: "Notifications", arg: "notifications", consolePath: "/notification" }, { name: "Project Dashboard", arg: "dashboard", consolePath: "/overview" }, { name: "Project Settings", arg: "settings", consolePath: "/settings/general" }, From a6c3aec258d55a4012f8404d07238477a882c4c5 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Thu, 6 Jul 2023 20:02:30 +0000 Subject: [PATCH 110/320] 12.4.3 --- npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 1e9c7e9c395..1f8651a0e91 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "firebase-tools", - "version": "12.4.2", + "version": "12.4.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-tools", - "version": "12.4.2", + "version": "12.4.3", "license": "MIT", "dependencies": { "@google-cloud/pubsub": "^3.0.1", diff --git a/package.json b/package.json index 39244402cda..20fa744fa17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "firebase-tools", - "version": "12.4.2", + "version": "12.4.3", "description": "Command-Line Interface for Firebase", "main": "./lib/index.js", "bin": { From 48b226f29c08103e2c1892513c46d62103353eb3 Mon Sep 17 00:00:00 2001 From: Google Open Source Bot Date: Thu, 6 Jul 2023 20:02:43 +0000 Subject: [PATCH 111/320] [firebase-release] Removed change log and reset repo after 12.4.3 release --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07dd3b508f7..e69de29bb2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +0,0 @@ -- Fixed incorrect links in `firebase open hosting` and `firebase open crash`. (#6073) -- Released Firebase Emulator UI v1.11.7, which includes preview support for multiple Firestore databases. (#6079) From 3bcc6712f81f9c8e882b6c5e5e41869a1d24f824 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Thu, 6 Jul 2023 14:05:58 -0700 Subject: [PATCH 112/320] VSCode plugin: Handle service accounts better (#6078) --- firebase-vscode/common/messaging/protocol.ts | 5 +- firebase-vscode/src/cli.ts | 72 ++++++++++++++----- firebase-vscode/src/workflow.ts | 69 +++++++++--------- firebase-vscode/webviews/SidebarApp.tsx | 19 +++-- .../webviews/components/AccountSection.tsx | 42 ++++++----- .../webviews/components/ProjectSection.tsx | 2 +- firebase-vscode/webviews/globals/ux-text.ts | 4 ++ src/requireAuth.ts | 16 ++++- 8 files changed, 145 insertions(+), 84 deletions(-) diff --git a/firebase-vscode/common/messaging/protocol.ts b/firebase-vscode/common/messaging/protocol.ts index ec79deefe5e..eedd4bbb249 100644 --- a/firebase-vscode/common/messaging/protocol.ts +++ b/firebase-vscode/common/messaging/protocol.ts @@ -21,14 +21,13 @@ export interface WebviewToExtensionParamsMap { requestChangeUser: { user: User | ServiceAccountUser }; /** Trigger project selection */ - selectProject: { email: string }; + selectProject: {}; /** * Runs `firebase init hosting` command. * TODO(hsubox76): Generalize to work for all `firebase init` products. */ selectAndInitHostingFolder: { projectId: string, - email: string, singleAppSupport: boolean }; @@ -91,7 +90,7 @@ export interface ExtensionToWebviewParamsMap { /** * This can potentially call multiple webviews to notify of user selection. */ - notifyUserChanged: { email: string }; + notifyUserChanged: { user: User | ServiceAccountUser }; /** * Notifies webview when user has successfully selected a hosting folder diff --git a/firebase-vscode/src/cli.ts b/firebase-vscode/src/cli.ts index beae5b8a777..d89db2e2fcb 100644 --- a/firebase-vscode/src/cli.ts +++ b/firebase-vscode/src/cli.ts @@ -18,40 +18,76 @@ import { Account, User } from "../../src/types/auth"; import { Options } from "../../src/options"; import { currentOptions, getCommandOptions } from "./options"; import { setInquirerOptions } from "./stubs/inquirer-stub"; -import { ServiceAccount } from "../common/types"; +import { ServiceAccount, ServiceAccountUser } from "../common/types"; import { listChannels } from "../../src/hosting/api"; import { ChannelWithId } from "../common/messaging/types"; import { pluginLogger } from "./logger-wrapper"; import { Config } from "../../src/config"; +import { currentUser } from "./workflow"; +import { setAccessToken } from "../../src/apiv2"; + +/** + * Try to get a service account by calling requireAuth() without + * providing any account info. + */ +async function getServiceAccount() { + let email = null; + try { + email = (await requireAuth({})) || null; + } catch (e) { + pluginLogger.debug('No service account found (this may be normal), requireAuth error output:', + e.original || e); + } + return email; +} /** * Wrap the CLI's requireAuth() which is normally run before every command * requiring user to be logged in. The CLI automatically supplies it with * account info if found in configstore so we need to fill that part in. */ -async function requireAuthWrapper(showError: boolean = true) { +async function requireAuthWrapper(showError: boolean = true): Promise { // Try to get global default from configstore. For some reason this is // often overwritten when restarting the extension. pluginLogger.debug('requireAuthWrapper'); + let authFound = false; let account = getGlobalDefaultAccount(); if (!account) { // If nothing in configstore top level, grab the first "additionalAccount" const accounts = getAllAccounts(); - if (accounts.length > 0) { - account = accounts[0]; - setGlobalDefaultAccount(account); + for (const additionalAccount of accounts) { + if (additionalAccount.user.email === currentUser.email) { + account = additionalAccount; + setGlobalDefaultAccount(account); + } } } - // `requireAuth()` will register the token with apiv2, and if account is - // still null at this point, it will use google-auth-library - // to find the service account. + if (account) { + authFound = true; + } + const commandOptions = await getCommandOptions(undefined, { + ...currentOptions + }); + // `requireAuth()` is not just a check, but will also register SERVICE + // ACCOUNT tokens in memory as a variable in apiv2.ts, which is needed + // for subsequent API calls. Warning: this variable takes precedence + // over Google login tokens and must be removed if a Google + // account is the current user. try { - const commandOptions = await getCommandOptions(undefined, { - ...currentOptions, - ...account, - }); - await requireAuth(commandOptions); + const serviceAccountEmail = await getServiceAccount(); + // Priority 1: Service account exists and is the current selected user + if (serviceAccountEmail && currentUser.email === serviceAccountEmail) { + await requireAuth(commandOptions); + } else if (account) { + // Priority 2: Google login account exists and is the currently selected + // user + // Priority 3: Google login account exists and there is no selected user + // Clear service account access token from memory in apiv2. + setAccessToken(); + await requireAuth({...commandOptions, ...account}); + } } catch (e) { + // No service account or google login found. if (showError) { pluginLogger.error('requireAuth error', e.original || e); vscode.window.showErrorMessage("Not logged in", { @@ -68,7 +104,7 @@ async function requireAuthWrapper(showError: boolean = true) { } // If we reach here, there is either a google account or no error on // requireAuth (which means there is a service account or glogin) - return true; + return authFound; } export async function getAccounts(): Promise> { @@ -76,11 +112,11 @@ export async function getAccounts(): Promise> { const accounts: Array = getAllAccounts(); pluginLogger.debug(`Found ${accounts.length} non-service accounts.`); // Get other accounts (assuming service account for now, could also be glogin) - const otherAuthExists = await requireAuthWrapper(false); - if (otherAuthExists) { - pluginLogger.debug(`Found service account`); + const serviceAccountEmail = await getServiceAccount(); + if (serviceAccountEmail) { + pluginLogger.debug(`Found service account: ${serviceAccountEmail}`); accounts.push({ - user: { email: "service_account", type: "service_account" }, + user: { email: serviceAccountEmail, type: "service_account" }, }); } return accounts; diff --git a/firebase-vscode/src/workflow.ts b/firebase-vscode/src/workflow.ts index 7ec6186cc6f..5327aa871f0 100644 --- a/firebase-vscode/src/workflow.ts +++ b/firebase-vscode/src/workflow.ts @@ -33,7 +33,7 @@ import { import { ServiceAccountUser } from "../common/types"; let users: Array = []; -let currentUserEmail = ""; +export let currentUser: User | ServiceAccountUser; // Stores a mapping from user email to list of projects for that user let projectsUserMapping = new Map(); let channels = null; @@ -71,24 +71,22 @@ async function promptUserForProject( function updateCurrentUser( users: User[], broker: ExtensionBrokerImpl, - newUserEmail?: string + newUser?: User | ServiceAccountUser ) { - if (newUserEmail) { - if (newUserEmail === currentUserEmail) { - return currentUserEmail; - } else { - currentUserEmail = newUserEmail; + if (newUser) { + if (newUser.email !== currentUser.email) { + currentUser = newUser; } } - if (!newUserEmail) { + if (!newUser) { if (users.length > 0) { - currentUserEmail = users[0].email; + currentUser = users[0]; } else { - currentUserEmail = null; + currentUser = null; } } - broker.send("notifyUserChanged", { email: currentUserEmail }); - return currentUserEmail; + broker.send("notifyUserChanged", { user: currentUser }); + return currentUser; } export async function setupWorkflow( @@ -107,7 +105,7 @@ export async function setupWorkflow( vscode.workspace.workspaceFolders[0].uri ); shouldWriteDebug = workspaceConfig.get('debug'); - debugLogPath= workspaceConfig.get('debugLogPath'); + debugLogPath = workspaceConfig.get('debugLogPath'); useFrameworks = workspaceConfig.get('useFrameworks'); npmPath = workspaceConfig.get('npmPath'); if (npmPath) { @@ -124,7 +122,7 @@ export async function setupWorkflow( // Sets up CLI logger to log to console process.env.DEBUG = 'true'; setupLoggers(); - + // Only log to file if firebase.debug extension setting is true. if (shouldWriteDebug) { // Re-implement file logger call from ../../src/bin/firebase.ts to not bring @@ -132,18 +130,18 @@ export async function setupWorkflow( const rootFolders = getRootFolders(); const filePath = debugLogPath || path.join(rootFolders[0], 'firebase-plugin-debug.log'); pluginLogger.info('Logging to path', filePath); - logger.add( - new transports.File({ - level: "debug", - filename: filePath, - format: format.printf((info) => { - const segments = [info.message, ...(info[SPLAT] || [])] - .map(tryStringify); - return `[${info.level}] ${stripAnsi(segments.join(" "))}`; - }), - }) - ); - } + logger.add( + new transports.File({ + level: "debug", + filename: filePath, + format: format.printf((info) => { + const segments = [info.message, ...(info[SPLAT] || [])] + .map(tryStringify); + return `[${info.level}] ${stripAnsi(segments.join(" "))}`; + }), + }) + ); + } /** * Call pluginLogger with log arguments received from webview. @@ -168,7 +166,7 @@ export async function setupWorkflow( // User login state await fetchUsers(); broker.send("notifyUsers", { users }); - currentUserEmail = updateCurrentUser(users, broker); + currentUser = updateCurrentUser(users, broker, currentUser); if (users.length > 0) { await fetchChannels(); } @@ -187,7 +185,7 @@ export async function setupWorkflow( const accounts = await getAccounts(); users = accounts.map((account) => account.user); broker.send("notifyUsers", { users }); - currentUserEmail = updateCurrentUser(users, broker); + currentUser = updateCurrentUser(users, broker); } catch (e) { // ignored } @@ -206,10 +204,10 @@ export async function setupWorkflow( users.push(user); if (users) { broker.send("notifyUsers", { users }); - currentUserEmail = updateCurrentUser( + currentUser = updateCurrentUser( users, broker, - user.email + user ); } }); @@ -219,8 +217,8 @@ export async function setupWorkflow( { user: User | ServiceAccountUser } ) => { if (users.some((user) => user.email === requestedUser.email)) { - currentUserEmail = requestedUser.email; - broker.send("notifyUserChanged", { email: currentUserEmail }); + currentUser = requestedUser; + broker.send("notifyUserChanged", { user: currentUser }); } }); @@ -259,8 +257,11 @@ export async function setupWorkflow( broker.send("notifyChannels", { channels }); } - async function selectProject({ email }) { + async function selectProject() { let projectId; + const isServiceAccount = + (currentUser as ServiceAccountUser).type === "service_account"; + const email = currentUser.email; if (process.env.MONOSPACE_ENV) { pluginLogger.debug('selectProject: found MONOSPACE_ENV, ' + 'prompting user using external flow'); @@ -280,7 +281,7 @@ export async function setupWorkflow( } catch (e) { pluginLogger.error(e); } - } else if (email === 'service_account') { + } else if (isServiceAccount) { /** * Non-Monospace service account case: get the service account's only * linked project. diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx index 5a5b4c61175..e3f75f7a2ed 100644 --- a/firebase-vscode/webviews/SidebarApp.tsx +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -18,7 +18,7 @@ export function SidebarApp() { const [hostingState, setHostingState] = useState(null); const [env, setEnv] = useState<{ isMonospace: boolean }>(); const [channels, setChannels] = useState(null); - const [userEmail, setUserEmail] = useState(null); + const [user, setUser] = useState(null); /** * null - has not finished checking yet * empty array - finished checking, no users logged in @@ -81,9 +81,9 @@ export function SidebarApp() { setProjectId(projectId); }); - broker.on("notifyUserChanged", ({ email }) => { - webLogger.debug("notifyUserChanged:", email); - setUserEmail(email); + broker.on("notifyUserChanged", ({ user }) => { + webLogger.debug("notifyUserChanged:", user.email); + setUser(user); }); broker.on("notifyHostingInitDone", ({ projectId, folderPath }) => { @@ -100,14 +100,13 @@ export function SidebarApp() { function setupHosting() { broker.send("selectAndInitHostingFolder", { projectId, - email: userEmail!, // Safe to assume user email is already there singleAppSupport: true, }); } const accountSection = ( @@ -126,10 +125,10 @@ export function SidebarApp() { <> {accountSection} - {!!userEmail && ( - + {!!user && ( + )} - {isHostingOnboarded && !!userEmail && !!projectId && ( + {isHostingOnboarded && !!user && !!projectId && ( )} - {!isHostingOnboarded && !!userEmail && !!projectId && ( + {!isHostingOnboarded && !!user && !!projectId && ( { setupHosting(); diff --git a/firebase-vscode/webviews/components/AccountSection.tsx b/firebase-vscode/webviews/components/AccountSection.tsx index 47bd62054ac..dba9ddc3896 100644 --- a/firebase-vscode/webviews/components/AccountSection.tsx +++ b/firebase-vscode/webviews/components/AccountSection.tsx @@ -14,12 +14,16 @@ import { ServiceAccountUser } from "../../common/types"; import { User } from "../../../src/types/auth"; import { TEXT } from "../globals/ux-text"; +interface UserWithType extends User { + type?: string; +} + export function AccountSection({ - userEmail, + user, allUsers, isMonospace, }: { - userEmail: string | null; + user: UserWithType | ServiceAccountUser | null; allUsers: Array | null; isMonospace: boolean; }) { @@ -27,7 +31,7 @@ export function AccountSection({ const usersLoaded = !!allUsers; // Default: initial users check hasn't completed let currentUserElement: ReactElement | string = TEXT.LOGIN_PROGRESS; - if (usersLoaded && !allUsers.length) { + if (usersLoaded && (!allUsers.length || !user)) { // Users loaded but no user was found if (isMonospace) { // Monospace: this is an error, should have found a workspace @@ -43,10 +47,14 @@ export function AccountSection({ } } else if (usersLoaded && allUsers.length > 0) { // Users loaded, at least one user was found - if (isMonospace && userEmail === "service_account") { - currentUserElement = TEXT.MONOSPACE_LOGGED_IN; + if (user.type === "service_account") { + if (isMonospace) { + currentUserElement = TEXT.MONOSPACE_LOGGED_IN; + } else { + currentUserElement = TEXT.VSCE_SERVICE_ACCOUNT_LOGGED_IN; + } } else { - currentUserElement = userEmail; + currentUserElement = user.email; } } return ( @@ -70,7 +78,7 @@ export function AccountSection({ {userDropdownVisible ? ( toggleUserDropdown(false)} /> @@ -83,19 +91,19 @@ export function AccountSection({ // TODO(roman): Convert to a better menu function UserSelectionMenu({ - userEmail, + user, allUsers, onClose, isMonospace, }: { - userEmail: string; + user: UserWithType | ServiceAccountUser; allUsers: Array; onClose: Function; isMonospace: boolean; }) { return ( <> - + { broker.send("addUser"); @@ -105,7 +113,7 @@ function UserSelectionMenu({ Sign in another user... - {allUsers.map((user) => ( + {allUsers.map((user: UserWithType | ServiceAccountUser) => ( { broker.send("requestChangeUser", { user }); @@ -113,22 +121,24 @@ function UserSelectionMenu({ }} key={user.email} > - {isMonospace && user.email === "service_account" - ? TEXT.MONOSPACE_LOGIN_SELECTION_ITEM + {user?.type === "service_account" + ? isMonospace + ? TEXT.MONOSPACE_LOGIN_SELECTION_ITEM + : TEXT.VSCE_SERVICE_ACCOUNT_SELECTION_ITEM : user.email} ))} { // You can't log out of a service account - userEmail !== "service_account" && ( + user.type !== "service_account" && ( { - broker.send("logout", { email: userEmail }); + broker.send("logout", { email: user.email }); onClose(); }} > - Sign Out {userEmail} + Sign Out {user.email} ) } diff --git a/firebase-vscode/webviews/components/ProjectSection.tsx b/firebase-vscode/webviews/components/ProjectSection.tsx index 40ca46c3b29..34c6e4b3d30 100644 --- a/firebase-vscode/webviews/components/ProjectSection.tsx +++ b/firebase-vscode/webviews/components/ProjectSection.tsx @@ -44,7 +44,7 @@ export function ProjectSection({ export function initProjectSelection(userEmail: string | null) { if (userEmail) { - broker.send("selectProject", { email: userEmail }); + broker.send("selectProject"); } else { broker.send("showMessage", { msg: "Not logged in", diff --git a/firebase-vscode/webviews/globals/ux-text.ts b/firebase-vscode/webviews/globals/ux-text.ts index d4d84521a1c..3703b1b2c16 100644 --- a/firebase-vscode/webviews/globals/ux-text.ts +++ b/firebase-vscode/webviews/globals/ux-text.ts @@ -12,6 +12,10 @@ export const TEXT = { MONOSPACE_LOGIN_SELECTION_ITEM: "Default credentials", + VSCE_SERVICE_ACCOUNT_LOGGED_IN: "Logged in with service account", + + VSCE_SERVICE_ACCOUNT_SELECTION_ITEM: "service account", + MONOSPACE_LOGIN_FAIL: "Unable to find default credentials", GOOGLE_SIGN_IN: "Sign in with Google", diff --git a/src/requireAuth.ts b/src/requireAuth.ts index caaa985f96f..2e1ee156158 100644 --- a/src/requireAuth.ts +++ b/src/requireAuth.ts @@ -33,15 +33,25 @@ function getAuthClient(config: GoogleAuthOptions): GoogleAuth { /** * Retrieves and sets the access token for the current user. + * Returns account email if found. * @param options CLI options. * @param authScopes scopes to be obtained. */ -async function autoAuth(options: Options, authScopes: string[]): Promise { +async function autoAuth(options: Options, authScopes: string[]): Promise { const client = getAuthClient({ scopes: authScopes, projectId: options.project }); const token = await client.getAccessToken(); token !== null ? apiv2.setAccessToken(token) : false; + let clientEmail; + try { + const credentials = await client.getCredentials(); + clientEmail = credentials.client_email; + } catch (e) { + // Make sure any error here doesn't block the CLI, but log it. + logger.debug(`Error getting account credentials.`); + } + if (!options.isVSCE && isMonospaceEnv()) { await selectProjectInMonospace({ projectRoot: options.config.projectDir, @@ -49,13 +59,15 @@ async function autoAuth(options: Options, authScopes: string[]): Promise { isVSCE: options.isVSCE, }); } + + return clientEmail; } /** * Ensures that there is an authenticated user. * @param options CLI options. */ -export async function requireAuth(options: any): Promise { +export async function requireAuth(options: any): Promise { api.setScopes([scopes.CLOUD_PLATFORM, scopes.FIREBASE_PLATFORM]); options.authScopes = api.getScopes(); From 7a9d6f2567c0cdcf0f16b531a02b23258599f434 Mon Sep 17 00:00:00 2001 From: blidd-google <112491344+blidd-google@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:04:16 -0400 Subject: [PATCH 113/320] Disables KeepAlive timeout when debugger is attached to the functions emulator (#6069) Node.js 19 introduced a change that sets `keepAlive` to true by default, with a default keep-alive duration of 5 seconds. This change broke our functions emulator behavior when a debugger was attached, as the Node.js HTTP server would consider the connection to be idle when a breakpoint was hit and disconnect after 5 seconds. This PR disables HTTP Keep-Alive and sets the socket timeout to 0 so that breakpoints won't cause the connection to timeout. Fixes https://github.com/firebase/firebase-tools/issues/5991. --- CHANGELOG.md | 1 + src/emulator/functionsRuntimeWorker.ts | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb2d..e0c337f63b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +Disables KeepAlive timeout when debugger is attached to the functions emulator. (#6069) diff --git a/src/emulator/functionsRuntimeWorker.ts b/src/emulator/functionsRuntimeWorker.ts index 8442c32cb1a..cf4e86f086d 100644 --- a/src/emulator/functionsRuntimeWorker.ts +++ b/src/emulator/functionsRuntimeWorker.ts @@ -125,7 +125,12 @@ export class RuntimeWorker { }); } - request(req: http.RequestOptions, resp: http.ServerResponse, body?: unknown): Promise { + request( + req: http.RequestOptions, + resp: http.ServerResponse, + body?: unknown, + debug?: boolean + ): Promise { if (this.triggerKey !== FREE_WORKER_KEY) { this.logInfo(`Beginning execution of "${this.triggerKey}"`); } @@ -176,6 +181,10 @@ export class RuntimeWorker { const piped = _resp.pipe(resp); piped.on("finish", () => finishReq("finish")); }); + if (debug) { + proxy.setSocketKeepAlive(false); + proxy.setTimeout(0); + } proxy.on("timeout", () => { this.logger.log( "ERROR", @@ -367,7 +376,7 @@ export class RuntimeWorkerPool { if (debug) { await worker.sendDebugMsg(debug); } - return worker.request(req, resp, body); + return worker.request(req, resp, body, !!debug); } getIdleWorker(triggerId: string | undefined): RuntimeWorker | undefined { From eab791326b97eef0b9902512a288750d670fe8c7 Mon Sep 17 00:00:00 2001 From: Fred Zhang Date: Fri, 7 Jul 2023 12:54:32 -0700 Subject: [PATCH 114/320] Make firebase:database:list to always use the RTDB management API (#6063) * remove rtdbmanagement experiment * rm firedata api * m * avoid breaking changes * m * doc * Update database-instances-list.ts * Update CHANGELOG.md --- CHANGELOG.md | 1 + src/commands/database-instances-list.ts | 80 +++++++++---------------- src/gcp/firedata.ts | 40 ------------- 3 files changed, 29 insertions(+), 92 deletions(-) delete mode 100644 src/gcp/firedata.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c337f63b8..6727ddeea8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ Disables KeepAlive timeout when debugger is attached to the functions emulator. (#6069) +Fixed an issue where `database:list` would have inaccurate results. (#6063) diff --git a/src/commands/database-instances-list.ts b/src/commands/database-instances-list.ts index 5328715b1bc..35f79bbc98a 100644 --- a/src/commands/database-instances-list.ts +++ b/src/commands/database-instances-list.ts @@ -1,12 +1,11 @@ -import { Command } from "../command"; const Table = require("cli-table"); + +import { Command } from "../command"; import * as clc from "colorette"; import * as ora from "ora"; import { logger } from "../logger"; import { requirePermissions } from "../requirePermissions"; -import { needProjectNumber } from "../projectUtils"; -import * as firedata from "../gcp/firedata"; import { Emulators } from "../emulator/types"; import { warnEmulatorNotSupported } from "../emulator/commandUtils"; import * as experiments from "../experiments"; @@ -18,31 +17,13 @@ import { parseDatabaseLocation, } from "../management/database"; -function logInstances(instances: DatabaseInstance[]): void { - if (instances.length === 0) { - logger.info(clc.bold("No database instances found.")); - return; - } - const tableHead = ["Database Instance Name", "Location", "Type", "State"]; - const table = new Table({ head: tableHead, style: { head: ["green"] } }); - instances.forEach((db) => { - table.push([db.name, db.location, db.type, db.state]); - }); - - logger.info(table.toString()); -} - -function logInstancesCount(count = 0): void { - if (count === 0) { - return; - } - logger.info(""); - logger.info(`${count} database instance(s) total.`); -} - -export let command = new Command("database:instances:list") +export const command = new Command("database:instances:list") .description("list realtime database instances, optionally filtered by a specified location") .before(requirePermissions, ["firebasedatabase.instances.list"]) + .option( + "-l, --location ", + "(optional) location for the database instance, defaults to all regions" + ) .before(warnEmulatorNotSupported, Emulators.DATABASE) .action(async (options: any) => { const location = parseDatabaseLocation(options.location, DatabaseLocation.ANY); @@ -50,39 +31,34 @@ export let command = new Command("database:instances:list") "Preparing the list of your Firebase Realtime Database instances" + `${location === DatabaseLocation.ANY ? "" : ` for location: ${location}`}` ).start(); - let instances; - if (experiments.isEnabled("rtdbmanagement")) { - const projectId = needProjectId(options); - try { - instances = await listDatabaseInstances(projectId, location); - } catch (err: any) { - spinner.fail(); - throw err; - } - spinner.succeed(); - logInstances(instances); - logInstancesCount(instances.length); - return instances; - } - const projectNumber = await needProjectNumber(options); + const projectId = needProjectId(options); + let instances: DatabaseInstance[] = []; try { - instances = await firedata.listDatabaseInstances(projectNumber); + instances = await listDatabaseInstances(projectId, location); } catch (err: any) { spinner.fail(); throw err; } spinner.succeed(); - for (const instance of instances) { - logger.info(instance.instance); + if (instances.length === 0) { + logger.info(clc.bold("No database instances found.")); + return; + } + // TODO: remove rtdbmanagement experiment in the next major release. + if (!experiments.isEnabled("rtdbmanagement")) { + for (const instance of instances) { + logger.info(instance.name); + } + logger.info(`Project ${options.project} has ${instances.length} database instances`); + return instances; + } + const tableHead = ["Database Instance Name", "Location", "Type", "State"]; + const table = new Table({ head: tableHead, style: { head: ["green"] } }); + for (const db of instances) { + table.push([db.name, db.location, db.type, db.state]); } - logger.info(`Project ${options.project} has ${instances.length} database instances`); + logger.info(table.toString()); + logger.info(`${instances.length} database instance(s) total.`); return instances; }); - -if (experiments.isEnabled("rtdbmanagement")) { - command = command.option( - "-l, --location ", - "(optional) location for the database instance, defaults to us-central1" - ); -} diff --git a/src/gcp/firedata.ts b/src/gcp/firedata.ts deleted file mode 100644 index 796aba02445..00000000000 --- a/src/gcp/firedata.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { firedataOrigin } from "../api"; -import { Client } from "../apiv2"; -import { logger } from "../logger"; -import * as utils from "../utils"; - -export interface DatabaseInstance { - // The globally unique name of the Database instance. - // Required to be URL safe. ex: 'red-ant' - instance: string; -} - -function _handleErrorResponse(response: any): any { - if (response.body && response.body.error) { - return utils.reject(response.body.error, { code: 2 }); - } - - logger.debug("[firedata] error:", response.status, response.body); - return utils.reject("Unexpected error encountered with FireData.", { - code: 2, - }); -} - -/** - * List Realtime Database instances - * @param projectNumber Project from which you want to list databases. - * @return the list of databases. - */ -export async function listDatabaseInstances(projectNumber: string): Promise { - const client = new Client({ urlPrefix: firedataOrigin, apiVersion: "v1" }); - const response = await client.get<{ instance: DatabaseInstance[] }>( - `/projects/${projectNumber}/databases`, - { - resolveOnHTTPError: true, - } - ); - if (response.status === 200) { - return response.body.instance; - } - return _handleErrorResponse(response); -} From 2a30b5dc403ac064ad249653f6a99295d4509373 Mon Sep 17 00:00:00 2001 From: egilmorez Date: Fri, 7 Jul 2023 14:54:39 -0700 Subject: [PATCH 115/320] Clarifying what the CLI does with dynamic content on next.js (per customer feedback). (#6093) --- src/frameworks/docs/nextjs.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/frameworks/docs/nextjs.md b/src/frameworks/docs/nextjs.md index 4f8f5e4e65d..dad8d3754f5 100644 --- a/src/frameworks/docs/nextjs.md +++ b/src/frameworks/docs/nextjs.md @@ -71,6 +71,9 @@ and [getStaticPaths](https://nextjs.org/docs/basic-features/data-fetching/get-st The {{firebase_cli}} will detect usage of [getServerSideProps](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props). +In such cases the {{cli}} will deploy functions to {{cloud_functions_full}} to run dynamic +server code. You can view information about these functions, such as their domain and runtime configuration, in the [Firebase console](https://console.firebase.google.com/project/_/functions). + ## Configure {{hosting}} behavior with `next.config.js` From c37634abd3b3b83c34cc46fbbef685073d35a850 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Fri, 7 Jul 2023 15:33:25 -0700 Subject: [PATCH 116/320] Rewrite `src/localFunction.js` in TypeScript. (#6092) `src/localFunction.js` is used to power the `functions:shell` command. We need to make substantial changes to it to properly support 2nd Gen functions (https://github.com/firebase/firebase-tools/issues/6089). Rewriting the source in modern TypeScript as a prep. --- CHANGELOG.md | 4 +- src/functionsShellCommandAction.ts | 4 +- src/localFunction.js | 221 ------------------------- src/localFunction.ts | 250 +++++++++++++++++++++++++++++ src/test/localFunction.spec.js | 64 -------- src/test/localFunction.spec.ts | 73 +++++++++ 6 files changed, 327 insertions(+), 289 deletions(-) delete mode 100644 src/localFunction.js create mode 100644 src/localFunction.ts delete mode 100644 src/test/localFunction.spec.js create mode 100644 src/test/localFunction.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6727ddeea8c..5a02bc44461 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,2 @@ -Disables KeepAlive timeout when debugger is attached to the functions emulator. (#6069) -Fixed an issue where `database:list` would have inaccurate results. (#6063) +- Disables KeepAlive timeout when debugger is attached to the functions emulator. (#6069) +- Fixed an issue where `database:list` would have inaccurate results. (#6063) diff --git a/src/functionsShellCommandAction.ts b/src/functionsShellCommandAction.ts index 9d637803aae..44280b53db9 100644 --- a/src/functionsShellCommandAction.ts +++ b/src/functionsShellCommandAction.ts @@ -6,7 +6,7 @@ import * as request from "request"; import * as util from "util"; import { FunctionsServer } from "./serve/functions"; -import * as LocalFunction from "./localFunction"; +import LocalFunction from "./localFunction"; import * as utils from "./utils"; import { logger } from "./logger"; import * as shell from "./emulator/functionsEmulatorShell"; @@ -99,7 +99,7 @@ export const actionFunction = async (options: Options) => { if (emulator.emulatedFunctions.includes(trigger.id)) { const localFunction = new LocalFunction(trigger, emulator.urls, emulator); const triggerNameDotNotation = trigger.name.replace(/-/g, "."); - _.set(context, triggerNameDotNotation, localFunction.call); + _.set(context, triggerNameDotNotation, localFunction.makeFn()); } } context.help = diff --git a/src/localFunction.js b/src/localFunction.js deleted file mode 100644 index 629e69241ec..00000000000 --- a/src/localFunction.js +++ /dev/null @@ -1,221 +0,0 @@ -"use strict"; - -var _ = require("lodash"); -var request = require("request"); - -var { encodeFirestoreValue } = require("./firestore/encodeFirestoreValue"); -var utils = require("./utils"); - -/** - * @constructor - * @this LocalFunction - * - * @param {object} trigger - * @param {object=} urls - * @param {object=} controller - */ -var LocalFunction = function (trigger, urls, controller) { - const isCallable = _.get(trigger, ["labels", "deployment-callable"], "false"); - - this.id = trigger.id; - this.name = trigger.name; - this.eventTrigger = trigger.eventTrigger; - this.httpsTrigger = trigger.httpsTrigger; - this.controller = controller; - this.url = _.get(urls, this.id); - - if (this.httpsTrigger) { - if (isCallable == "true") { - this.call = this._constructCallableFunc.bind(this); - } else { - this.call = request.defaults({ - callback: this._requestCallBack, - baseUrl: this.url, - uri: "", - }); - } - } else { - this.call = this._call.bind(this); - } -}; - -LocalFunction.prototype._isDatabaseFunc = function (eventTrigger) { - return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Database"; -}; - -LocalFunction.prototype._isFirestoreFunc = function (eventTrigger) { - return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Firestore"; -}; - -LocalFunction.prototype._substituteParams = function (resource, params) { - var wildcardRegex = new RegExp("{[^/{}]*}", "g"); - return resource.replace(wildcardRegex, function (wildcard) { - var wildcardNoBraces = wildcard.slice(1, -1); // .slice removes '{' and '}' from wildcard - var sub = _.get(params, wildcardNoBraces); - return sub || wildcardNoBraces + utils.randomInt(1, 9); - }); -}; - -LocalFunction.prototype._constructCallableFunc = function (data, opts) { - opts = opts || {}; - - var headers = {}; - if (opts.instanceIdToken) { - headers["Firebase-Instance-ID-Token"] = opts.instanceIdToken; - } - - return request.post({ - callback: this._requestCallBack, - baseUrl: this.url, - uri: "", - body: { data: data }, - json: true, - headers: headers, - }); -}; - -LocalFunction.prototype._constructAuth = function (auth, authType) { - if (_.get(auth, "admin") || _.get(auth, "variable")) { - return auth; // User is providing the wire auth format already. - } - if (typeof authType !== "undefined") { - switch (authType) { - case "USER": - return { - variable: { - uid: _.get(auth, "uid", ""), - token: _.get(auth, "token", {}), - }, - }; - case "ADMIN": - if (_.get(auth, "uid") || _.get(auth, "token")) { - throw new Error("authType and auth are incompatible."); - } - return { admin: true }; - case "UNAUTHENTICATED": - if (_.get(auth, "uid") || _.get(auth, "token")) { - throw new Error("authType and auth are incompatible."); - } - return { admin: false }; - default: - throw new Error( - "Unrecognized authType, valid values are: " + "ADMIN, USER, and UNAUTHENTICATED" - ); - } - } - if (auth) { - return { - variable: { - uid: auth.uid, - token: auth.token || {}, - }, - }; - } - // Default to admin - return { admin: true }; -}; - -LocalFunction.prototype._makeFirestoreValue = function (input) { - if (typeof input === "undefined" || _.isEmpty(input)) { - // Document does not exist. - return {}; - } - if (typeof input !== "object") { - throw new Error("Firestore data must be key-value pairs."); - } - var currentTime = new Date().toISOString(); - return { - fields: encodeFirestoreValue(input), - createTime: currentTime, - updateTime: currentTime, - }; -}; - -LocalFunction.prototype._requestCallBack = function (err, response, body) { - if (err) { - return console.warn("\nERROR SENDING REQUEST: " + err); - } - var status = response ? response.statusCode + ", " : ""; - - // If the body is a string we want to check if we can parse it as JSON - // and pretty-print it. We can't blindly stringify because stringifying - // a string results in some ugly escaping. - var bodyString = body; - if (typeof body === "string") { - try { - bodyString = JSON.stringify(JSON.parse(bodyString), null, 2); - } catch (e) { - // Ignore - } - } else { - bodyString = JSON.stringify(body, null, 2); - } - - return console.log("\nRESPONSE RECEIVED FROM FUNCTION: " + status + bodyString); -}; - -LocalFunction.prototype._call = function (data, opts) { - opts = opts || {}; - var operationType; - var dataPayload; - - if (this.httpsTrigger) { - this.controller.call(this.name, data || {}); - } else if (this.eventTrigger) { - if (this._isDatabaseFunc(this.eventTrigger)) { - operationType = utils.last(this.eventTrigger.eventType.split(".")); - switch (operationType) { - case "create": - dataPayload = { - data: null, - delta: data, - }; - break; - case "delete": - dataPayload = { - data: data, - delta: null, - }; - break; - default: - // 'update' or 'write' - dataPayload = { - data: data.before, - delta: data.after, - }; - } - opts.resource = this._substituteParams(this.eventTrigger.resource, opts.params); - opts.auth = this._constructAuth(opts.auth, opts.authType); - this.controller.call(this.name, dataPayload, opts); - } else if (this._isFirestoreFunc(this.eventTrigger)) { - operationType = utils.last(this.eventTrigger.eventType.split(".")); - switch (operationType) { - case "create": - dataPayload = { - value: this._makeFirestoreValue(data), - oldValue: {}, - }; - break; - case "delete": - dataPayload = { - value: {}, - oldValue: this._makeFirestoreValue(data), - }; - break; - default: - // 'update' or 'write' - dataPayload = { - value: this._makeFirestoreValue(data.after), - oldValue: this._makeFirestoreValue(data.before), - }; - } - opts.resource = this._substituteParams(this.eventTrigger.resource, opts.params); - this.controller.call(this.name, dataPayload, opts); - } else { - this.controller.call(this.name, data || {}, opts); - } - } - return "Successfully invoked function."; -}; - -module.exports = LocalFunction; diff --git a/src/localFunction.ts b/src/localFunction.ts new file mode 100644 index 00000000000..82534e1eda8 --- /dev/null +++ b/src/localFunction.ts @@ -0,0 +1,250 @@ +import * as request from "request"; + +import * as utils from "./utils"; +import { encodeFirestoreValue } from "./firestore/encodeFirestoreValue"; +import { EmulatedTriggerDefinition } from "./emulator/functionsEmulatorShared"; +import { FunctionsEmulatorShell } from "./emulator/functionsEmulatorShell"; +import { AuthMode } from "./emulator/events/types"; + +type AuthType = "USER" | "ADMIN" | "UNAUTHENTICATED"; + +type EventOptions = { + params?: Record; + authType?: AuthType; + auth?: Partial & { + uid?: string; + token?: string; + }; + resource?: string; +}; + +/** + * LocalFunction produces EmulatedTriggerDefinition into a function that can be called inside the nodejs repl. + */ +export default class LocalFunction { + private url?: string; + private paramWildcardRegex = new RegExp("{[^/{}]*}", "g"); + + constructor( + private trigger: EmulatedTriggerDefinition, + urls: Record, + private controller: FunctionsEmulatorShell + ) { + this.url = urls[trigger.id]; + } + + private substituteParams(resource: string, params?: Record): string { + if (!params) { + return resource; + } + return resource.replace(this.paramWildcardRegex, (wildcard: string) => { + const wildcardNoBraces = wildcard.slice(1, -1); // .slice removes '{' and '}' from wildcard + const sub = params?.[wildcardNoBraces]; + return sub || `${wildcardNoBraces}${utils.randomInt(1, 9)}`; + }); + } + + private constructCallableFunc( + data: string | object, + opts: { instanceIdToken?: string } + ): request.Request { + opts = opts || {}; + + const headers: Record = {}; + if (opts.instanceIdToken) { + headers["Firebase-Instance-ID-Token"] = opts.instanceIdToken; + } + + return request.post({ + callback: (...args) => this.requestCallBack(...args), + baseUrl: this.url, + uri: "", + body: { data }, + json: true, + headers: headers, + }); + } + + constructAuth(auth?: EventOptions["auth"], authType?: AuthType): AuthMode { + if (auth?.admin || auth?.variable) { + return { + admin: auth.admin || false, + variable: auth.variable, + }; // User is providing the wire auth format already. + } + if (authType) { + switch (authType) { + case "USER": + return { + admin: false, + variable: { + uid: auth?.uid ?? "", + token: auth?.token ?? {}, + }, + }; + case "ADMIN": + if (auth?.uid || auth?.token) { + throw new Error("authType and auth are incompatible."); + } + return { admin: true }; + case "UNAUTHENTICATED": + if (auth?.uid || auth?.token) { + throw new Error("authType and auth are incompatible."); + } + return { admin: false }; + default: + throw new Error( + "Unrecognized authType, valid values are: " + "ADMIN, USER, and UNAUTHENTICATED" + ); + } + } + if (auth) { + return { + admin: false, + variable: { + uid: auth.uid ?? "", + token: auth.token || {}, + }, + }; + } + // Default to admin + return { admin: true }; + } + + makeFirestoreValue(input?: unknown): { + fields?: Record; + createTime?: string; + updateTime?: string; + } { + if ( + typeof input === "undefined" || + input === null || + (typeof input === "object" && Object.keys(input).length === 0) + ) { + // Document does not exist. + return {}; + } + if (typeof input !== "object") { + throw new Error("Firestore data must be key-value pairs."); + } + const currentTime = new Date().toISOString(); + return { + fields: encodeFirestoreValue(input), + createTime: currentTime, + updateTime: currentTime, + }; + } + + private requestCallBack(err: unknown, response: request.Response, body: string | object): void { + if (err) { + return console.warn("\nERROR SENDING REQUEST: " + err); + } + const status = response ? response.statusCode + ", " : ""; + + // If the body is a string we want to check if we can parse it as JSON + // and pretty-print it. We can't blindly stringify because stringifying + // a string results in some ugly escaping. + let bodyString = body; + if (typeof bodyString === "string") { + try { + bodyString = JSON.stringify(JSON.parse(bodyString), null, 2); + } catch (e) { + // Ignore + } + } else { + bodyString = JSON.stringify(body, null, 2); + } + + return console.log("\nRESPONSE RECEIVED FROM FUNCTION: " + status + bodyString); + } + + private isDatabaseFn(eventTrigger: Required["eventTrigger"]): boolean { + return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Database"; + } + private isFirestoreFunc( + eventTrigger: Required["eventTrigger"] + ): boolean { + return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Firestore"; + } + + private triggerEvent(data: unknown, opts?: EventOptions): void { + opts = opts || {}; + let operationType; + let dataPayload; + + if (this.trigger.httpsTrigger) { + this.controller.call(this.trigger.name, data || {}, opts); + } else if (this.trigger.eventTrigger) { + if (this.isDatabaseFn(this.trigger.eventTrigger)) { + operationType = utils.last(this.trigger.eventTrigger.eventType.split(".")); + switch (operationType) { + case "create": + dataPayload = { + data: null, + delta: data, + }; + break; + case "delete": + dataPayload = { + data: data, + delta: null, + }; + break; + default: + // 'update' or 'write' + dataPayload = { + data: (data as any).before, + delta: (data as any).after, + }; + } + opts.resource = this.substituteParams(this.trigger.eventTrigger.resource!, opts.params); + opts.auth = this.constructAuth(opts.auth, opts.authType); + this.controller.call(this.trigger.name, dataPayload, opts); + } else if (this.isFirestoreFunc(this.trigger.eventTrigger)) { + operationType = utils.last(this.trigger.eventTrigger.eventType.split(".")); + switch (operationType) { + case "create": + dataPayload = { + value: this.makeFirestoreValue(data), + oldValue: {}, + }; + break; + case "delete": + dataPayload = { + value: {}, + oldValue: this.makeFirestoreValue(data), + }; + break; + default: + // 'update' or 'write' + dataPayload = { + value: this.makeFirestoreValue((data as any).after), + oldValue: this.makeFirestoreValue((data as any).before), + }; + } + opts.resource = this.substituteParams(this.trigger.eventTrigger.resource!, opts.params); + this.controller.call(this.trigger.name, dataPayload, opts); + } else { + this.controller.call(this.trigger.name, data || {}, opts); + } + } + return console.log("Successfully invoked function."); + } + + makeFn() { + if (this.trigger.httpsTrigger) { + const isCallable = !!this.trigger.labels?.["deployment-callable"]; + if (isCallable) { + return (data: any, opt: any) => this.constructCallableFunc(data, opt); + } else { + return request.defaults({ + callback: (...args) => this.requestCallBack(...args), + baseUrl: this.url, + uri: "", + }); + } + } else { + return (data: any, opt: any) => this.triggerEvent(data, opt); + } + } +} diff --git a/src/test/localFunction.spec.js b/src/test/localFunction.spec.js deleted file mode 100644 index 2b47d7b2879..00000000000 --- a/src/test/localFunction.spec.js +++ /dev/null @@ -1,64 +0,0 @@ -"use strict"; - -var chai = require("chai"); -var expect = chai.expect; - -var LocalFunction = require("../localFunction"); - -describe("localFunction._constructAuth", function () { - var lf = new LocalFunction({}); - - describe("#_constructAuth", function () { - var constructAuth = lf._constructAuth; - - it("warn if opts.auth and opts.authType are conflicting", function () { - expect(function () { - return constructAuth({ uid: "something" }, "UNAUTHENTICATED"); - }).to.throw("incompatible"); - - expect(function () { - return constructAuth({ uid: "something" }, "ADMIN"); - }).to.throw("incompatible"); - }); - - it("construct the correct auth for admin users", function () { - expect(constructAuth(undefined, "ADMIN")).to.deep.equal({ admin: true }); - }); - - it("construct the correct auth for unauthenticated users", function () { - expect(constructAuth(undefined, "UNAUTHENTICATED")).to.deep.equal({ - admin: false, - }); - }); - - it("construct the correct auth for authenticated users", function () { - expect(constructAuth(undefined, "USER")).to.deep.equal({ - variable: { uid: "", token: {} }, - }); - expect(constructAuth({ uid: "11" }, "USER")).to.deep.equal({ - variable: { uid: "11", token: {} }, - }); - }); - - it("leaves auth untouched if it already follows wire format", function () { - var auth = { variable: { uid: "something" } }; - expect(constructAuth(auth)).to.deep.equal(auth); - }); - }); - - describe("localFunction._makeFirestoreValue", function () { - var makeFirestoreValue = lf._makeFirestoreValue; - - it("returns {} when there is no data", function () { - expect(makeFirestoreValue()).to.deep.equal({}); - expect(makeFirestoreValue(null)).to.deep.equal({}); - expect(makeFirestoreValue({})).to.deep.equal({}); - }); - - it("throws error when data is not key-value pairs", function () { - expect(function () { - return makeFirestoreValue("string"); - }).to.throw(Error); - }); - }); -}); diff --git a/src/test/localFunction.spec.ts b/src/test/localFunction.spec.ts new file mode 100644 index 00000000000..e1f7c9f6c78 --- /dev/null +++ b/src/test/localFunction.spec.ts @@ -0,0 +1,73 @@ +import { expect } from "chai"; + +import LocalFunction from "../localFunction"; +import { EmulatedTriggerDefinition } from "../emulator/functionsEmulatorShared"; +import { FunctionsEmulatorShell } from "../emulator/functionsEmulatorShell"; + +const EMULATED_TRIGGER: EmulatedTriggerDefinition = { + id: "fn", + region: "us-central1", + platform: "gcfv1", + availableMemoryMb: 1024, + entryPoint: "test-resource", + name: "test-resource", + timeoutSeconds: 3, +}; + +describe("constructAuth", () => { + const lf = new LocalFunction(EMULATED_TRIGGER, {}, {} as FunctionsEmulatorShell); + + describe("#_constructAuth", () => { + it("warn if opts.auth and opts.authType are conflicting", () => { + expect(() => { + return lf.constructAuth({ uid: "something" }, "UNAUTHENTICATED"); + }).to.throw("incompatible"); + + expect(() => { + return lf.constructAuth({ admin: false, uid: "something" }, "ADMIN"); + }).to.throw("incompatible"); + }); + + it("construct the correct auth for admin users", () => { + expect(lf.constructAuth(undefined, "ADMIN")).to.deep.equal({ admin: true }); + }); + + it("construct the correct auth for unauthenticated users", () => { + expect(lf.constructAuth(undefined, "UNAUTHENTICATED")).to.deep.equal({ + admin: false, + }); + }); + + it("construct the correct auth for authenticated users", () => { + expect(lf.constructAuth(undefined, "USER")).to.deep.equal({ + admin: false, + variable: { uid: "", token: {} }, + }); + expect(lf.constructAuth({ uid: "11" }, "USER")).to.deep.equal({ + admin: false, + variable: { uid: "11", token: {} }, + }); + }); + + it("leaves auth untouched if it already follows wire format", () => { + const auth = { admin: false, variable: { uid: "something" } }; + expect(lf.constructAuth(auth)).to.deep.equal(auth); + }); + }); +}); + +describe("makeFirestoreValue", () => { + const lf = new LocalFunction(EMULATED_TRIGGER, {}, {} as FunctionsEmulatorShell); + + it("returns {} when there is no data", () => { + expect(lf.makeFirestoreValue()).to.deep.equal({}); + expect(lf.makeFirestoreValue(null)).to.deep.equal({}); + expect(lf.makeFirestoreValue({})).to.deep.equal({}); + }); + + it("throws error when data is not key-value pairs", () => { + expect(() => { + return lf.makeFirestoreValue("string"); + }).to.throw(Error); + }); +}); From f4581809c3af60fe58c10a143df0679f76d4b216 Mon Sep 17 00:00:00 2001 From: Christina Holland Date: Mon, 10 Jul 2023 13:27:36 -0700 Subject: [PATCH 117/320] VSCode plugin: Add UX improvements (#6091) --- firebase-vscode/common/messaging/protocol.ts | 10 ++- firebase-vscode/package-lock.json | 4 +- firebase-vscode/package.json | 2 +- firebase-vscode/src/logger-wrapper.ts | 74 +++++++++++++++ firebase-vscode/src/workflow.ts | 49 +++------- firebase-vscode/webviews/SidebarApp.tsx | 7 +- .../webviews/components/AccountSection.tsx | 90 +++++++++++++------ .../webviews/components/DeployPanel.tsx | 29 ++++-- firebase-vscode/webviews/globals/ux-text.ts | 12 ++- 9 files changed, 197 insertions(+), 80 deletions(-) diff --git a/firebase-vscode/common/messaging/protocol.ts b/firebase-vscode/common/messaging/protocol.ts index eedd4bbb249..79203a82a60 100644 --- a/firebase-vscode/common/messaging/protocol.ts +++ b/firebase-vscode/common/messaging/protocol.ts @@ -64,7 +64,7 @@ export interface WebviewToExtensionParamsMap { /** * Equivalent to the `firebase emulators:start` command. */ - launchEmulators : { + launchEmulators: { emulatorUiSelections: EmulatorUiSelections, }; @@ -96,7 +96,11 @@ export interface ExtensionToWebviewParamsMap { * Notifies webview when user has successfully selected a hosting folder * and it has been written to firebase.json. */ - notifyHostingInitDone: { projectId: string, folderPath?: string }; + notifyHostingInitDone: { + projectId: string, + folderPath?: string + framework?: string + }; /** * Notify webview of status of deployment attempt. @@ -119,7 +123,7 @@ export interface ExtensionToWebviewParamsMap { notifyPreviewChannelResponse: { id: string }; notifyEmulatorsStopped: {}; - notifyRunningEmulatorInfo: RunningEmulatorInfo ; + notifyRunningEmulatorInfo: RunningEmulatorInfo; notifyEmulatorImportFolder: { folder: string }; } diff --git a/firebase-vscode/package-lock.json b/firebase-vscode/package-lock.json index ccbdb5e7b61..1d261781bf8 100644 --- a/firebase-vscode/package-lock.json +++ b/firebase-vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "firebase-vscode", - "version": "0.0.23-alpha.2", + "version": "0.0.23-alpha.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "firebase-vscode", - "version": "0.0.23-alpha.2", + "version": "0.0.23-alpha.3", "dependencies": { "@vscode/codicons": "0.0.30", "@vscode/webview-ui-toolkit": "^1.2.1", diff --git a/firebase-vscode/package.json b/firebase-vscode/package.json index e18acd3939c..2539455a726 100644 --- a/firebase-vscode/package.json +++ b/firebase-vscode/package.json @@ -3,7 +3,7 @@ "displayName": "firebase-vscode", "publisher": "firebase", "description": "VSCode Extension for Firebase", - "version": "0.0.23-alpha.2", + "version": "0.0.23-alpha.3", "engines": { "vscode": "^1.69.0" }, diff --git a/firebase-vscode/src/logger-wrapper.ts b/firebase-vscode/src/logger-wrapper.ts index f736403f32a..54ab62d1300 100644 --- a/firebase-vscode/src/logger-wrapper.ts +++ b/firebase-vscode/src/logger-wrapper.ts @@ -1,10 +1,24 @@ +import * as path from "path"; +import * as vscode from "vscode"; +import { transports, format } from "winston"; +import Transport from "winston-transport"; +import stripAnsi from "strip-ansi"; +import { SPLAT } from "triple-beam"; import { logger as cliLogger } from "../../src/logger"; +import { setupLoggers, tryStringify } from "../../src/utils"; import { setInquirerLogger } from "./stubs/inquirer-stub"; +import { getRootFolders } from "./config-files"; export const pluginLogger: Record void> = {}; const logLevels = ['debug', 'info', 'log', 'warn', 'error']; +const outputChannel = vscode.window.createOutputChannel('Firebase'); + +export function showOutputChannel() { + outputChannel.show(); +} + for (const logLevel of logLevels) { pluginLogger[logLevel] = (...args) => { const prefixedArgs = ['[Firebase Plugin]', ...args]; @@ -12,4 +26,64 @@ for (const logLevel of logLevels) { }; } +/** + * Logging setup for logging to console and to file. + */ +export function logSetup({ shouldWriteDebug, debugLogPath }: { + shouldWriteDebug: boolean, + debugLogPath: string +}) { + // Log to console (use built in CLI functionality) + process.env.DEBUG = 'true'; + setupLoggers(); + + // Log to file + // Only log to file if firebase.debug extension setting is true. + if (shouldWriteDebug) { + // Re-implement file logger call from ../../src/bin/firebase.ts to not bring + // in the entire firebase.ts file + const rootFolders = getRootFolders(); + const filePath = debugLogPath || path.join(rootFolders[0], 'firebase-plugin-debug.log'); + pluginLogger.info('Logging to path', filePath); + cliLogger.add( + new transports.File({ + level: "debug", + filename: filePath, + format: format.printf((info) => { + const segments = [info.message, ...(info[SPLAT] || [])] + .map(tryStringify); + return `[${info.level}] ${stripAnsi(segments.join(" "))}`; + }), + }) + ); + cliLogger.add( + new VSCodeOutputTransport({ level: "info" }) + ); + } +} + +/** + * Custom Winston transport that writes to VSCode output channel. + * Write only "info" and greater to avoid too much spam from "debug". + */ +class VSCodeOutputTransport extends Transport { + constructor(opts) { + super(opts); + } + log(info, callback) { + setImmediate(() => { + this.emit('logged', info); + }); + const segments = [info.message, ...(info[SPLAT] || [])] + .map(tryStringify); + const text = `[${info.level}] ${stripAnsi(segments.join(" "))}`; + + if (info.level !== 'debug') { + // info or greater: write to output window + outputChannel.appendLine(text); + } + + callback(); + } +} setInquirerLogger(pluginLogger); diff --git a/firebase-vscode/src/workflow.ts b/firebase-vscode/src/workflow.ts index 5327aa871f0..2be4e0e1975 100644 --- a/firebase-vscode/src/workflow.ts +++ b/firebase-vscode/src/workflow.ts @@ -1,8 +1,4 @@ -import * as path from "path"; import * as vscode from "vscode"; -import { transports, format } from "winston"; -import stripAnsi from "strip-ansi"; -import { SPLAT } from "triple-beam"; import { ExtensionContext, workspace } from "vscode"; import { FirebaseProjectMetadata } from "../../src/types/project"; @@ -19,16 +15,13 @@ import { import { User } from "../../src/types/auth"; import { currentOptions } from "./options"; import { selectProjectInMonospace } from "../../src/monospace"; -import { setupLoggers, tryStringify } from "../../src/utils"; -import { pluginLogger } from "./logger-wrapper"; -import { logger } from '../../src/logger'; +import { logSetup, pluginLogger, showOutputChannel } from "./logger-wrapper"; import { discover } from "../../src/frameworks"; import { setEnabled } from "../../src/experiments"; import { readAndSendFirebaseConfigs, setupFirebaseJsonAndRcFileSystemWatcher, - updateFirebaseRCProject, - getRootFolders + updateFirebaseRCProject } from "./config-files"; import { ServiceAccountUser } from "../common/types"; @@ -37,6 +30,7 @@ export let currentUser: User | ServiceAccountUser; // Stores a mapping from user email to list of projects for that user let projectsUserMapping = new Map(); let channels = null; +let currentFramework: string | undefined; async function fetchUsers() { const accounts = await getAccounts(); @@ -116,32 +110,8 @@ export async function setupWorkflow( if (useFrameworks) { setEnabled('webframeworks', true); } - /** - * Logging setup for logging to console and to file. - */ - // Sets up CLI logger to log to console - process.env.DEBUG = 'true'; - setupLoggers(); - // Only log to file if firebase.debug extension setting is true. - if (shouldWriteDebug) { - // Re-implement file logger call from ../../src/bin/firebase.ts to not bring - // in the entire firebase.ts file - const rootFolders = getRootFolders(); - const filePath = debugLogPath || path.join(rootFolders[0], 'firebase-plugin-debug.log'); - pluginLogger.info('Logging to path', filePath); - logger.add( - new transports.File({ - level: "debug", - filename: filePath, - format: format.printf((info) => { - const segments = [info.message, ...(info[SPLAT] || [])] - .map(tryStringify); - return `[${info.level}] ${stripAnsi(segments.join(" "))}`; - }), - }) - ); - } + logSetup({ shouldWriteDebug, debugLogPath }); /** * Call pluginLogger with log arguments received from webview. @@ -227,6 +197,9 @@ export async function setupWorkflow( broker.on("selectAndInitHostingFolder", selectAndInitHosting); broker.on("hostingDeploy", async ({ target: deployTarget }) => { + showOutputChannel(); + pluginLogger.info(`Starting deployment of project ` + + `${currentOptions.projectId} to channel: ${deployTarget}`); const { success, consoleUrl, hostingUrl } = await deployToHosting( currentOptions.config, deployTarget @@ -323,14 +296,14 @@ export async function setupWorkflow( } async function selectAndInitHosting({ projectId, singleAppSupport }) { - let discoveredFramework; + currentFramework = undefined; // Note: discover() takes a few seconds. No need to block users that don't // have frameworks support enabled. if (useFrameworks) { - discoveredFramework = useFrameworks && await discover(currentOptions.cwd, false); + currentFramework = useFrameworks && await discover(currentOptions.cwd, false); pluginLogger.debug('Searching for a web framework in this project.'); } - if (discoveredFramework) { + if (currentFramework) { pluginLogger.debug('Detected web framework, launching frameworks init.'); await initHosting({ spa: singleAppSupport, @@ -358,7 +331,7 @@ export async function setupWorkflow( } readAndSendFirebaseConfigs(broker, context); broker.send("notifyHostingInitDone", - { projectId, folderPath: currentOptions.cwd }); + { projectId, folderPath: currentOptions.cwd, framework: currentFramework }); await fetchChannels(true); } } diff --git a/firebase-vscode/webviews/SidebarApp.tsx b/firebase-vscode/webviews/SidebarApp.tsx index e3f75f7a2ed..768377bf7d1 100644 --- a/firebase-vscode/webviews/SidebarApp.tsx +++ b/firebase-vscode/webviews/SidebarApp.tsx @@ -19,6 +19,7 @@ export function SidebarApp() { const [env, setEnv] = useState<{ isMonospace: boolean }>(); const [channels, setChannels] = useState(null); const [user, setUser] = useState(null); + const [framework, setFramework] = useState(null); /** * null - has not finished checking yet * empty array - finished checking, no users logged in @@ -86,9 +87,12 @@ export function SidebarApp() { setUser(user); }); - broker.on("notifyHostingInitDone", ({ projectId, folderPath }) => { + broker.on("notifyHostingInitDone", ({ projectId, folderPath, framework }) => { webLogger.debug(`notifyHostingInitDone: ${projectId}, ${folderPath}`); setHostingOnboarded(true); + if (framework) { + setFramework(framework); + } }); broker.on("notifyHostingDeploy", ({ success }) => { @@ -134,6 +138,7 @@ export function SidebarApp() { setHostingState={setHostingState} projectId={projectId} channels={channels} + framework={framework} /> )} diff --git a/firebase-vscode/webviews/components/AccountSection.tsx b/firebase-vscode/webviews/components/AccountSection.tsx index dba9ddc3896..02f7ec8e79f 100644 --- a/firebase-vscode/webviews/components/AccountSection.tsx +++ b/firebase-vscode/webviews/components/AccountSection.tsx @@ -57,12 +57,22 @@ export function AccountSection({ currentUserElement = user.email; } } - return ( -
    -