From 8c96c81c14e77c5e171c3247bec13047e6c953d9 Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Wed, 15 Jun 2022 13:59:12 -0700 Subject: [PATCH 01/63] Change logging severity for passing callable auth validation (#1138) --- src/common/providers/https.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/providers/https.ts b/src/common/providers/https.ts index b3bed0e6d..e8d1b1a9c 100644 --- a/src/common/providers/https.ts +++ b/src/common/providers/https.ts @@ -618,7 +618,7 @@ async function checkTokens( } if (errs.length == 0) { - logger.info('Callable request verification passed', logPayload); + logger.debug('Callable request verification passed', logPayload); } else { logger.warn( `Callable request verification failed: ${errs.join(' ')}`, From c06b4fe17e861294947d5935ae9a24c1b946eb43 Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Thu, 16 Jun 2022 11:12:31 -0700 Subject: [PATCH 02/63] Bump admin SDK version. Remove vendored APIs + sniffing (#1139) * Bump admin SDK version. Remove vendored APIs + sniffing * Bump node version; remove tests for old node versions * Package lock * Update v2 rtdb to expose RawRTDBEvent and RawRTDBCloudEventData (#1137) * Update v2 rtdb to expose RawRTDBEvent and RawRTDBCloudEventData This commit updates the v2 database provider to also expose the RawRTDB Events. This will be used in test-sdk when mocking returned DatabaseEvents. * Adding @hidden instead of @internal * Revert package lock * Run formatter Co-authored-by: Tyler Stark --- .github/workflows/test.yaml | 3 -- package.json | 4 +- src/common/providers/https.ts | 72 +++-------------------------------- src/v2/providers/database.ts | 4 +- 4 files changed, 10 insertions(+), 73 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 33242e9b8..099608df2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,8 +13,6 @@ jobs: strategy: matrix: node-version: - - 10.x - - 12.x - 14.x - 16.x steps: @@ -38,7 +36,6 @@ jobs: strategy: matrix: node-version: - - 12.x - 14.x - 16.x steps: diff --git a/package.json b/package.json index 03f56c851..8ffac83b1 100644 --- a/package.json +++ b/package.json @@ -229,9 +229,9 @@ "yargs": "^15.3.1" }, "peerDependencies": { - "firebase-admin": "^8.0.0 || ^9.0.0 || ^10.0.0" + "firebase-admin": "^10.0.0" }, "engines": { - "node": "^8.13.0 || >=10.10.0" + "node": ">=14.10.0" } } diff --git a/src/common/providers/https.ts b/src/common/providers/https.ts index e8d1b1a9c..fab4fe158 100644 --- a/src/common/providers/https.ts +++ b/src/common/providers/https.ts @@ -22,7 +22,8 @@ import * as cors from 'cors'; import * as express from 'express'; -import * as firebase from 'firebase-admin'; +import { DecodedAppCheckToken } from 'firebase-admin/app-check'; +import { DecodedIdToken } from 'firebase-admin/auth'; import * as logger from '../../logger'; @@ -40,60 +41,6 @@ export interface Request extends express.Request { rawBody: Buffer; } -// This is actually a firebase.appCheck.DecodedAppCheckToken, but -// that type may not be available in some supported SDK versions. -// Declare as an inline type, which DecodedAppCheckToken will be -// able to merge with. -// TODO: Replace with the real type once we bump the min-version of -// the admin SDK -interface DecodedAppCheckToken { - /** - * The issuer identifier for the issuer of the response. - * - * This value is a URL with the format - * `https://firebaseappcheck.googleapis.com/`, where `` is the - * same project number specified in the [`aud`](#aud) property. - */ - iss: string; - - /** - * The Firebase App ID corresponding to the app the token belonged to. - * - * As a convenience, this value is copied over to the [`app_id`](#app_id) property. - */ - sub: string; - - /** - * The audience for which this token is intended. - * - * This value is a JSON array of two strings, the first is the project number of your - * Firebase project, and the second is the project ID of the same project. - */ - aud: string[]; - - /** - * The App Check token's expiration time, in seconds since the Unix epoch. That is, the - * time at which this App Check token expires and should no longer be considered valid. - */ - exp: number; - - /** - * The App Check token's issued-at time, in seconds since the Unix epoch. That is, the - * time at which this App Check token was issued and should start to be considered - * valid.; - */ - iat: number; - - /** - * The App ID corresponding to the App the App Check token belonged to. - * - * This value is not actually one of the JWT token claims. It is added as a - * convenience, and is set as the value of the [`sub`](#sub) property. - */ - app_id: string; - [key: string]: any; -} - /** * The interface for AppCheck tokens verified in Callable functions */ @@ -107,7 +54,7 @@ export interface AppCheckData { */ export interface AuthData { uid: string; - token: firebase.auth.DecodedIdToken; + token: DecodedIdToken; } // This type is the direct v1 callable interface and is also an interface @@ -553,10 +500,8 @@ export function unsafeDecodeToken(token: string): unknown { * This is exposed only for testing. */ /** @internal */ -export function unsafeDecodeIdToken( - token: string -): firebase.auth.DecodedIdToken { - const decoded = unsafeDecodeToken(token) as firebase.auth.DecodedIdToken; +export function unsafeDecodeIdToken(token: string): DecodedIdToken { + const decoded = unsafeDecodeToken(token) as DecodedIdToken; decoded.uid = decoded.sub; return decoded; } @@ -642,7 +587,7 @@ export async function checkAuthToken( if (match) { const idToken = match[1]; try { - let authToken: firebase.auth.DecodedIdToken; + let authToken: DecodedIdToken; if (isDebugFeatureEnabled('skipTokenVerification')) { authToken = unsafeDecodeIdToken(idToken); } else { @@ -672,11 +617,6 @@ async function checkAppCheckToken( return 'MISSING'; } try { - if (!apps().admin.appCheck) { - throw new Error( - 'Cannot validate AppCheck token. Please update Firebase Admin SDK to >= v9.8.0' - ); - } let appCheckData; if (isDebugFeatureEnabled('skipTokenVerification')) { const decodedToken = unsafeDecodeAppCheckToken(appCheck); diff --git a/src/v2/providers/database.ts b/src/v2/providers/database.ts index b0a38c313..e0b410422 100644 --- a/src/v2/providers/database.ts +++ b/src/v2/providers/database.ts @@ -44,14 +44,14 @@ export const updatedEventType = 'google.firebase.database.ref.v1.updated'; /** @internal */ export const deletedEventType = 'google.firebase.database.ref.v1.deleted'; -/** @internal */ +/** @hidden */ export interface RawRTDBCloudEventData { ['@type']: 'type.googleapis.com/google.events.firebase.database.v1.ReferenceEventData'; data: any; delta: any; } -/** @internal */ +/** @hidden */ export interface RawRTDBCloudEvent extends CloudEvent { firebasedatabasehost: string; instance: string; From ea5edf90897938da55463922d44517671cbce43a Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Fri, 17 Jun 2022 13:52:20 -0700 Subject: [PATCH 03/63] Error logs always show up in Cloud Error Reporting (#1141) * Checkpoint * Make logging.error show up in Cloud Error Reporting * Make logging.error show up in Cloud Error Reporting * Lint fixes --- spec/logger.spec.ts | 14 ++------------ src/logger/common.ts | 6 ------ src/logger/compat.ts | 18 +++++++----------- src/logger/index.ts | 44 ++++++++++---------------------------------- 4 files changed, 19 insertions(+), 63 deletions(-) diff --git a/spec/logger.spec.ts b/spec/logger.spec.ts index c82497d31..54181b64d 100644 --- a/spec/logger.spec.ts +++ b/spec/logger.spec.ts @@ -2,12 +2,7 @@ import { expect } from 'chai'; import * as logger from '../src/logger'; -const SUPPORTS_STRUCTURED_LOGS = - parseInt(process.versions?.node?.split('.')?.[0] || '8', 10) >= 10; - -describe(`logger (${ - SUPPORTS_STRUCTURED_LOGS ? 'structured' : 'unstructured' -})`, () => { +describe('logger', () => { const stdoutWrite = process.stdout.write.bind(process.stdout); const stderrWrite = process.stderr.write.bind(process.stderr); let lastOut: string; @@ -30,12 +25,7 @@ describe(`logger (${ }); function expectOutput(last: string, entry: any) { - if (SUPPORTS_STRUCTURED_LOGS) { - return expect(JSON.parse(last.trim())).to.deep.eq(entry); - } else { - // legacy logging is not structured, but do a sanity check - return expect(last).to.include(entry.message); - } + return expect(JSON.parse(last.trim())).to.deep.eq(entry); } function expectStdout(entry: any) { diff --git a/src/logger/common.ts b/src/logger/common.ts index 020883bbb..38d2edd54 100644 --- a/src/logger/common.ts +++ b/src/logger/common.ts @@ -20,12 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// Determine if structured logs are supported (node >= 10). If something goes wrong, -// assume no since unstructured is safer. -/** @hidden */ -export const SUPPORTS_STRUCTURED_LOGS = - parseInt(process.versions?.node?.split('.')?.[0] || '8', 10) >= 10; - // Map LogSeverity types to their equivalent `console.*` method. /** @hidden */ export const CONSOLE_SEVERITY: { diff --git a/src/logger/compat.ts b/src/logger/compat.ts index 7300a197b..f001a95a4 100644 --- a/src/logger/compat.ts +++ b/src/logger/compat.ts @@ -21,23 +21,19 @@ // SOFTWARE. import { format } from 'util'; -import { - CONSOLE_SEVERITY, - SUPPORTS_STRUCTURED_LOGS, - UNPATCHED_CONSOLE, -} from './common'; +import { CONSOLE_SEVERITY, UNPATCHED_CONSOLE } from './common'; /** @hidden */ function patchedConsole(severity: string): (data: any, ...args: any[]) => void { return function(data: any, ...args: any[]): void { - if (SUPPORTS_STRUCTURED_LOGS) { - UNPATCHED_CONSOLE[CONSOLE_SEVERITY[severity]]( - JSON.stringify({ severity, message: format(data, ...args) }) - ); - return; + let message = format(data, ...args); + if (severity === 'ERROR') { + message = new Error(message).stack || message; } - UNPATCHED_CONSOLE[CONSOLE_SEVERITY[severity]](data, ...args); + UNPATCHED_CONSOLE[CONSOLE_SEVERITY[severity]]( + JSON.stringify({ severity, message }) + ); }; } diff --git a/src/logger/index.ts b/src/logger/index.ts index 02750f845..52effcbd7 100644 --- a/src/logger/index.ts +++ b/src/logger/index.ts @@ -22,11 +22,7 @@ import { format } from 'util'; -import { - CONSOLE_SEVERITY, - SUPPORTS_STRUCTURED_LOGS, - UNPATCHED_CONSOLE, -} from './common'; +import { CONSOLE_SEVERITY, UNPATCHED_CONSOLE } from './common'; /** * `LogSeverity` indicates the detailed severity of the log entry. See [LogSeverity](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity). @@ -90,30 +86,9 @@ function removeCircular(obj: any, refs: any[] = []): any { * @public */ export function write(entry: LogEntry) { - if (SUPPORTS_STRUCTURED_LOGS) { - UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]]( - JSON.stringify(removeCircular(entry)) - ); - return; - } - - let message = entry.message || ''; - const jsonPayload: { [key: string]: any } = {}; - let jsonKeyCount = 0; - for (const k in entry) { - if (!['severity', 'message'].includes(k)) { - jsonKeyCount++; - jsonPayload[k] = entry[k]; - } - } - if (jsonKeyCount > 0) { - message = `${message} ${JSON.stringify( - removeCircular(jsonPayload), - null, - 2 - )}`; - } - UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]](message); + UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]]( + JSON.stringify(removeCircular(entry)) + ); } /** @@ -173,9 +148,10 @@ function entryFromArgs(severity: LogSeverity, args: any[]): LogEntry { if (lastArg && typeof lastArg == 'object' && lastArg.constructor == Object) { entry = args.pop(); } - return Object.assign({}, entry, { - severity, - // mimic `console.*` behavior, see https://nodejs.org/api/console.html#console_console_log_data_args - message: format.apply(null, args), - }); + // mimic `console.*` behavior, see https://nodejs.org/api/console.html#console_console_log_data_args + let message = format.apply(null, args); + if (severity === 'ERROR' && !args.find((arg) => arg instanceof Error)) { + message = new Error(message).stack || message; + } + return { ...entry, severity, message }; } From 0b47d40c351f3457a00833bd24bbeb02967ff2ab Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Fri, 24 Jun 2022 16:45:10 -0700 Subject: [PATCH 04/63] Move to enforceAppCheck option (#1145) --- spec/common/providers/https.spec.ts | 66 ++++++++++++++++++++++++++++- src/common/providers/https.ts | 13 +++++- src/function-builder.ts | 7 +++ src/function-configuration.ts | 13 +++--- src/providers/https.ts | 2 +- src/v2/options.ts | 11 ++++- src/v2/providers/https.ts | 29 ++++++++++--- 7 files changed, 124 insertions(+), 17 deletions(-) diff --git a/spec/common/providers/https.spec.ts b/spec/common/providers/https.spec.ts index 8916a371a..83b2fe4ee 100644 --- a/spec/common/providers/https.spec.ts +++ b/spec/common/providers/https.spec.ts @@ -370,6 +370,10 @@ describe('onCallHandler', () => { const appCheckToken = generateUnsignedAppCheckToken(projectId, appId); await runCallableTest({ httpRequest: mockRequest(null, 'application/json', { appCheckToken }), + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: true, + }, expectedData: null, callableFunction: (data, context) => { return; @@ -390,7 +394,7 @@ describe('onCallHandler', () => { }); }); - it('should handle bad AppCheck token with callable option', async () => { + it('should handle bad AppCheck token with enforcement disabled', async () => { await runCallableTest({ httpRequest: mockRequest(null, 'application/json', { appCheckToken: 'FAKE', @@ -404,7 +408,7 @@ describe('onCallHandler', () => { }, callableOption: { cors: { origin: true, methods: 'POST' }, - allowInvalidAppCheckToken: true, + enforceAppCheck: false, }, expectedHttpResponse: { status: 200, @@ -414,6 +418,64 @@ describe('onCallHandler', () => { }); }); + it('should handle bad AppCheck token with enforcement enabled', async () => { + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + appCheckToken: 'FAKE', + }), + expectedData: null, + callableFunction: (data, context) => { + return; + }, + callableFunction2: (request) => { + return; + }, + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: true, + }, + expectedHttpResponse: { + status: 401, + headers: expectedResponseHeaders, + body: { + error: { + message: 'Unauthenticated', + status: 'UNAUTHENTICATED', + }, + }, + }, + }); + }); + + it('should handle no AppCheck token with enforcement enabled', async () => { + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + appCheckToken: 'MISSING', + }), + expectedData: null, + callableFunction: (data, context) => { + return; + }, + callableFunction2: (request) => { + return; + }, + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: true, + }, + expectedHttpResponse: { + status: 401, + headers: expectedResponseHeaders, + body: { + error: { + message: 'Unauthenticated', + status: 'UNAUTHENTICATED', + }, + }, + }, + }); + }); + it('should handle instance id', async () => { await runCallableTest({ httpRequest: mockRequest(null, 'application/json', { diff --git a/src/common/providers/https.ts b/src/common/providers/https.ts index fab4fe158..dc7de3c2b 100644 --- a/src/common/providers/https.ts +++ b/src/common/providers/https.ts @@ -643,7 +643,7 @@ type v2CallableHandler = (request: CallableRequest) => Res; /** @internal **/ export interface CallableOptions { cors: cors.CorsOptions; - allowInvalidAppCheckToken?: boolean; + enforceAppCheck?: boolean; } /** @internal */ @@ -679,7 +679,16 @@ function wrapOnCallHandler( if (tokenStatus.auth === 'INVALID') { throw new HttpsError('unauthenticated', 'Unauthenticated'); } - if (tokenStatus.app === 'INVALID' && !options.allowInvalidAppCheckToken) { + if (tokenStatus.app === 'INVALID') { + if (options.enforceAppCheck) { + throw new HttpsError('unauthenticated', 'Unauthenticated'); + } else { + logger.warn( + 'Allowing request with invalid AppCheck token because enforcement is disabled' + ); + } + } + if (tokenStatus.app === 'MISSING' && options.enforceAppCheck) { throw new HttpsError('unauthenticated', 'Unauthenticated'); } diff --git a/src/function-builder.ts b/src/function-builder.ts index 1fd4efb05..0c313c637 100644 --- a/src/function-builder.ts +++ b/src/function-builder.ts @@ -242,6 +242,13 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { } } + if ('allowInvalidAppCheckToken' in runtimeOptions) { + throw new Error( + 'runWith option "allowInvalidAppCheckToken" has been inverted and ' + + 'renamed "enforceAppCheck"' + ); + } + return true; } diff --git a/src/function-configuration.ts b/src/function-configuration.ts index 73cc64eac..2568d67a9 100644 --- a/src/function-configuration.ts +++ b/src/function-configuration.ts @@ -161,15 +161,18 @@ export interface RuntimeOptions { */ invoker?: 'public' | 'private' | string | string[]; - /* - * Allow requests with invalid App Check tokens on callable functions. - */ - allowInvalidAppCheckToken?: boolean; - /* * Secrets to bind to a function instance. */ secrets?: string[]; + + /** + * Determines whether Firebase AppCheck is enforced. + * When true, requests with invalid tokens autorespond with a 401 + * (Unauthorized) error. + * When false, requests with invalid tokens set context.app to undefiend. + */ + enforceAppCheck?: boolean; } export interface DeploymentOptions extends RuntimeOptions { diff --git a/src/providers/https.ts b/src/providers/https.ts index 842ebd84c..b50c9764b 100644 --- a/src/providers/https.ts +++ b/src/providers/https.ts @@ -110,7 +110,7 @@ export function _onCallWithOptions( handler(data, context); const func: any = onCallHandler( { - allowInvalidAppCheckToken: options.allowInvalidAppCheckToken, + enforceAppCheck: options.enforceAppCheck, cors: { origin: true, methods: 'POST' }, }, fixedLen diff --git a/src/v2/options.ts b/src/v2/options.ts index c2ebf5248..06bb9aebd 100644 --- a/src/v2/options.ts +++ b/src/v2/options.ts @@ -189,6 +189,14 @@ export interface GlobalOptions { * Secrets to bind to a function. */ secrets?: string[]; + + /** + * Determines whether Firebase AppCheck is enforced. + * When true, requests with invalid tokens autorespond with a 401 + * (Unauthorized) error. + * When false, requests with invalid tokens set event.app to undefiend. + */ + enforceAppCheck?: boolean; } let globalOptions: GlobalOptions | undefined; @@ -216,7 +224,8 @@ export function getGlobalOptions(): GlobalOptions { /** * Additional fields that can be set on any event-handling Cloud Function. */ -export interface EventHandlerOptions extends GlobalOptions { +export interface EventHandlerOptions + extends Omit { /** Whether failed executions should be delivered again. */ retry?: boolean; } diff --git a/src/v2/providers/https.ts b/src/v2/providers/https.ts index dad7355cd..3d9510e1c 100644 --- a/src/v2/providers/https.ts +++ b/src/v2/providers/https.ts @@ -44,7 +44,7 @@ import { GlobalOptions, SupportedRegion } from '../options'; export { Request, CallableRequest, FunctionsErrorCode, HttpsError }; /** - * Options that can be set on an individual HTTPS function. + * Options that can be set on an onRequest HTTPS function. */ export interface HttpsOptions extends Omit { /** HTTP functions can override global options and can specify multiple regions to deploy to. */ @@ -150,6 +150,19 @@ export interface HttpsOptions extends Omit { retry?: boolean; } +/** + * Options that can be set on a callable HTTPS function. + */ +export interface CallableOptions extends HttpsOptions { + /** + * Determines whether Firebase AppCheck is enforced. + * When true, requests with invalid tokens autorespond with a 401 + * (Unauthorized) error. + * When false, requests with invalid tokens set event.app to undefiend. + */ + enforceAppCheck?: boolean; +} + /** * Handles HTTPS requests. */ @@ -298,7 +311,7 @@ export function onRequest( * @returns A function that you can export and deploy. */ export function onCall>( - opts: HttpsOptions, + opts: CallableOptions, handler: (request: CallableRequest) => Return ): CallableFunction; /** @@ -310,15 +323,15 @@ export function onCall>( handler: (request: CallableRequest) => Return ): CallableFunction; export function onCall>( - optsOrHandler: HttpsOptions | ((request: CallableRequest) => Return), + optsOrHandler: CallableOptions | ((request: CallableRequest) => Return), handler?: (request: CallableRequest) => Return ): CallableFunction { - let opts: HttpsOptions; + let opts: CallableOptions; if (arguments.length == 1) { opts = {}; handler = optsOrHandler as (request: CallableRequest) => Return; } else { - opts = optsOrHandler as HttpsOptions; + opts = optsOrHandler as CallableOptions; } const origin = isDebugFeatureEnabled('enableCors') @@ -331,7 +344,11 @@ export function onCall>( // fix the length to prevent api versions from being mismatched. const fixedLen = (req: CallableRequest) => handler(req); const func: any = onCallHandler( - { cors: { origin, methods: 'POST' } }, + { + cors: { origin, methods: 'POST' }, + enforceAppCheck: + opts.enforceAppCheck ?? options.getGlobalOptions().enforceAppCheck, + }, fixedLen ); From e84438793940b6de8faa0703d4bd8c2fa9711c70 Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Sun, 26 Jun 2022 13:40:44 -0700 Subject: [PATCH 05/63] Put tests in a codebase (#1148) * Update v2 rtdb to expose RawRTDBEvent and RawRTDBCloudEventData (#1137) * Update v2 rtdb to expose RawRTDBEvent and RawRTDBCloudEventData This commit updates the v2 database provider to also expose the RawRTDB Events. This will be used in test-sdk when mocking returned DatabaseEvents. * Adding @hidden instead of @internal * Put tests in a codebase * Revert changes to package-lock.json * Format fix Co-authored-by: Tyler Stark Co-authored-by: Daniel Young Lee --- integration_test/firebase.json | 4 ++++ integration_test/run_tests.sh | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/integration_test/firebase.json b/integration_test/firebase.json index ce496e265..5ab884ea2 100644 --- a/integration_test/firebase.json +++ b/integration_test/firebase.json @@ -5,5 +5,9 @@ "firestore": { "rules": "firestore.rules", "indexes": "firestore.indexes.json" + }, + "functions": { + "source": "functions", + "codebase": "integration-tests" } } diff --git a/integration_test/run_tests.sh b/integration_test/run_tests.sh index 814ddc492..4c8e51d24 100755 --- a/integration_test/run_tests.sh +++ b/integration_test/run_tests.sh @@ -65,9 +65,9 @@ function delete_all_functions { # Try to delete, if there are errors it is because the project is already empty, # in that case do nothing. if [[ "${TOKEN}" == "" ]]; then - firebase functions:delete integrationTests v1 v2 --force --project=$PROJECT_ID || : & + firebase functions:delete integration-tests --force --project=$PROJECT_ID || : & else - firebase functions:delete integrationTests v1 v2 --force --project=$PROJECT_ID --token=$TOKEN || : & + firebase functions:delete integration-tests --force --project=$PROJECT_ID --token=$TOKEN || : & fi wait announce "Project emptied." From bebb3983da167e169a3dbb846e4c63c816965334 Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Mon, 27 Jun 2022 12:17:49 -0700 Subject: [PATCH 06/63] Rework apps, update admin, remove lodash (#1144) * Update admin; remove lodash * Adding missing file * Uncomment code --- package.json | 4 +- spec/common/providers/https.spec.ts | 26 ++--- spec/common/providers/tasks.spec.ts | 18 ++-- spec/fixtures/mockrequest.ts | 3 +- spec/v1/apps.spec.ts | 143 ---------------------------- spec/v1/cloud-functions.spec.ts | 15 +-- spec/v1/providers/database.spec.ts | 10 +- spec/v1/providers/firestore.spec.ts | 31 +++--- src/apps.ts | 134 -------------------------- src/cloud-functions.ts | 75 ++++++++------- src/common/app.ts | 69 ++++++++++++++ src/common/providers/database.ts | 19 ++-- src/common/providers/https.ts | 13 +-- src/common/providers/identity.ts | 16 ++-- src/common/providers/tasks.ts | 4 +- src/function-builder.ts | 48 +++++----- src/handler-builder.ts | 5 +- src/index.ts | 7 +- src/providers/analytics.ts | 90 ++++++++++++----- src/providers/database.ts | 26 ++--- src/providers/firestore.ts | 39 ++++---- src/providers/remoteConfig.ts | 2 - src/providers/testLab.ts | 24 +++-- src/utils.ts | 33 ++++--- src/v2/providers/database.ts | 8 +- tsconfig.release.json | 4 +- 26 files changed, 342 insertions(+), 524 deletions(-) delete mode 100644 spec/v1/apps.spec.ts delete mode 100644 src/apps.ts create mode 100644 src/common/app.ts diff --git a/package.json b/package.json index 8ffac83b1..168e595ac 100644 --- a/package.json +++ b/package.json @@ -184,7 +184,6 @@ "@types/express": "4.17.3", "cors": "^2.8.5", "express": "^4.17.1", - "lodash": "^4.17.14", "node-fetch": "^2.6.7" }, "devDependencies": { @@ -194,7 +193,6 @@ "@types/chai": "^4.1.7", "@types/chai-as-promised": "^7.1.0", "@types/jsonwebtoken": "^8.3.2", - "@types/lodash": "^4.14.135", "@types/mocha": "^5.2.7", "@types/mock-require": "^2.0.0", "@types/nock": "^10.0.3", @@ -234,4 +232,4 @@ "engines": { "node": ">=14.10.0" } -} +} \ No newline at end of file diff --git a/spec/common/providers/https.spec.ts b/spec/common/providers/https.spec.ts index 83b2fe4ee..fa13d0d8f 100644 --- a/spec/common/providers/https.spec.ts +++ b/spec/common/providers/https.spec.ts @@ -1,8 +1,8 @@ import { expect } from 'chai'; -import * as firebase from 'firebase-admin'; +import { App, deleteApp, initializeApp } from 'firebase-admin/app'; import * as sinon from 'sinon'; -import { apps as appsNamespace } from '../../../src/apps'; +import { getApp, setApp } from '../../../src/common/app'; import * as debug from '../../../src/common/debug'; import * as https from '../../../src/common/providers/https'; import * as mocks from '../../fixtures/credential/key.json'; @@ -76,7 +76,7 @@ async function runCallableTest(test: CallTest): Promise { } describe('onCallHandler', () => { - let app: firebase.app.App; + let app: App; before(() => { const credential = { @@ -92,16 +92,16 @@ describe('onCallHandler', () => { }; }, }; - app = firebase.initializeApp({ + app = initializeApp({ projectId: 'aProjectId', credential, }); - Object.defineProperty(appsNamespace(), 'admin', { get: () => app }); + setApp(app); }); after(() => { - app.delete(); - delete appsNamespace.singleton; + deleteApp(app); + setApp(undefined); }); it('should handle success', () => { @@ -288,7 +288,7 @@ describe('onCallHandler', () => { it('should handle auth', async () => { const mock = mockFetchPublicKeys(); - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const idToken = generateIdToken(projectId); await runCallableTest({ httpRequest: mockRequest(null, 'application/json', { @@ -313,7 +313,7 @@ describe('onCallHandler', () => { }); it('should reject bad auth', async () => { - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const idToken = generateUnsignedIdToken(projectId); await runCallableTest({ httpRequest: mockRequest(null, 'application/json', { @@ -341,7 +341,7 @@ describe('onCallHandler', () => { it('should handle AppCheck token', async () => { const mock = mockFetchAppCheckPublicJwks(); - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const appId = '123:web:abc'; const appCheckToken = generateAppCheckToken(projectId, appId); await runCallableTest({ @@ -365,7 +365,7 @@ describe('onCallHandler', () => { }); it('should reject bad AppCheck token', async () => { - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const appId = '123:web:abc'; const appCheckToken = generateUnsignedAppCheckToken(projectId, appId); await runCallableTest({ @@ -536,7 +536,7 @@ describe('onCallHandler', () => { }); it('should skip auth token verification', async () => { - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const idToken = generateUnsignedIdToken(projectId); await runCallableTest({ httpRequest: mockRequest(null, 'application/json', { @@ -560,7 +560,7 @@ describe('onCallHandler', () => { }); it('should skip app check token verification', async () => { - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const appId = '123:web:abc'; const appCheckToken = generateUnsignedAppCheckToken(projectId, appId); await runCallableTest({ diff --git a/spec/common/providers/tasks.spec.ts b/spec/common/providers/tasks.spec.ts index d3711a18f..d25d87068 100644 --- a/spec/common/providers/tasks.spec.ts +++ b/spec/common/providers/tasks.spec.ts @@ -21,9 +21,9 @@ // SOFTWARE. import { expect } from 'chai'; -import * as firebase from 'firebase-admin'; +import { App, deleteApp, initializeApp } from 'firebase-admin/app'; -import { apps as appsNamespace } from '../../../src/apps'; +import { getApp, setApp } from '../../../src/common/app'; import * as https from '../../../src/common/providers/https'; import { onDispatchHandler, @@ -78,7 +78,7 @@ export async function runTaskTest(test: TaskTest): Promise { } describe('onEnqueueHandler', () => { - let app: firebase.app.App; + let app: App; function mockEnqueueRequest( data: unknown, @@ -102,16 +102,16 @@ describe('onEnqueueHandler', () => { }; }, }; - app = firebase.initializeApp({ + app = initializeApp({ projectId: 'aProjectId', credential, }); - Object.defineProperty(appsNamespace(), 'admin', { get: () => app }); + setApp(app); }); after(() => { - app.delete(); - delete appsNamespace.singleton; + deleteApp(app); + setApp(undefined); }); it('should handle success', () => { @@ -201,7 +201,7 @@ describe('onEnqueueHandler', () => { }); it('should handle auth', async () => { - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const idToken = generateIdToken(projectId); await runTaskTest({ httpRequest: mockEnqueueRequest(null, 'application/json', { @@ -221,7 +221,7 @@ describe('onEnqueueHandler', () => { }); it('should accept unsigned auth too', async () => { - const projectId = appsNamespace().admin.options.projectId; + const projectId = getApp().options.projectId; const idToken = generateUnsignedIdToken(projectId); await runTaskTest({ httpRequest: mockEnqueueRequest(null, 'application/json', { diff --git a/spec/fixtures/mockrequest.ts b/spec/fixtures/mockrequest.ts index 5accb339e..60a0822c0 100644 --- a/spec/fixtures/mockrequest.ts +++ b/spec/fixtures/mockrequest.ts @@ -1,6 +1,5 @@ import * as jwt from 'jsonwebtoken'; import * as jwkToPem from 'jwk-to-pem'; -import * as _ from 'lodash'; import * as nock from 'nock'; import * as mockJWK from '../fixtures/credential/jwk.json'; import * as mockKey from '../fixtures/credential/key.json'; @@ -32,7 +31,7 @@ export function mockRequest( } = {} ) { const body: any = {}; - if (!_.isUndefined(data)) { + if (typeof data !== 'undefined') { body.data = data; } diff --git a/spec/v1/apps.spec.ts b/spec/v1/apps.spec.ts deleted file mode 100644 index 89a1b3f5b..000000000 --- a/spec/v1/apps.spec.ts +++ /dev/null @@ -1,143 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 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. - -import { expect } from 'chai'; -import { apps as appsNamespace } from '../../src/apps'; - -import * as firebase from 'firebase-admin'; -import * as _ from 'lodash'; -import * as sinon from 'sinon'; - -describe('apps', () => { - let apps: appsNamespace.Apps; - - beforeEach(() => { - apps = new appsNamespace.Apps(); - }); - - afterEach(() => { - _.forEach(firebase.apps, (app) => { - app.delete(); - }); - }); - - describe('retain/release', () => { - let clock: sinon.SinonFakeTimers; - - beforeEach(() => { - clock = sinon.useFakeTimers(); - }); - - afterEach(() => { - clock.restore(); - }); - - it('should retain/release ref counters appropriately', () => { - apps.retain(); - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 1, - }); - apps.release(); - clock.tick(appsNamespace.garbageCollectionInterval); - return Promise.resolve().then(() => { - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 0, - }); - }); - }); - - it('should only decrement counter after garbageCollectionInterval is up', () => { - apps.retain(); - apps.release(); - clock.tick(appsNamespace.garbageCollectionInterval / 2); - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 1, - }); - clock.tick(appsNamespace.garbageCollectionInterval / 2); - return Promise.resolve().then(() => { - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 0, - }); - }); - }); - - it('should call _destroyApp if app no longer used', () => { - const spy = sinon.spy(apps, '_destroyApp'); - apps.retain(); - apps.release(); - clock.tick(appsNamespace.garbageCollectionInterval); - return Promise.resolve().then(() => { - expect(spy.called).to.be.true; - }); - }); - - it('should not call _destroyApp if app used again while waiting for release', () => { - const spy = sinon.spy(apps, '_destroyApp'); - apps.retain(); - apps.release(); - clock.tick(appsNamespace.garbageCollectionInterval / 2); - apps.retain(); - clock.tick(appsNamespace.garbageCollectionInterval / 2); - return Promise.resolve().then(() => { - expect(spy.called).to.be.false; - }); - }); - - it('should increment ref counter for each subsequent retain', () => { - apps.retain(); - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 1, - }); - apps.retain(); - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 2, - }); - apps.retain(); - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 3, - }); - }); - - it('should work with staggering sets of retain/release', () => { - apps.retain(); - apps.release(); - clock.tick(appsNamespace.garbageCollectionInterval / 2); - apps.retain(); - apps.release(); - clock.tick(appsNamespace.garbageCollectionInterval / 2); - return Promise.resolve() - .then(() => { - // Counters are still 1 due second set of retain/release - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 1, - }); - clock.tick(appsNamespace.garbageCollectionInterval / 2); - }) - .then(() => { - // It's now been a full interval since the second set of retain/release - expect(_.get(apps, '_refCounter')).to.deep.equal({ - __admin__: 0, - }); - }); - }); - }); -}); diff --git a/spec/v1/cloud-functions.spec.ts b/spec/v1/cloud-functions.spec.ts index fec1bd580..ab4209025 100644 --- a/spec/v1/cloud-functions.spec.ts +++ b/spec/v1/cloud-functions.spec.ts @@ -21,7 +21,6 @@ // SOFTWARE. import { expect } from 'chai'; -import * as _ from 'lodash'; import { Change, @@ -176,9 +175,10 @@ describe('makeCloudFunction', () => { }); it('should construct the right context for event', () => { - const args: any = _.assign({}, cloudFunctionArgs, { + const args: any = { + ...cloudFunctionArgs, handler: (data: any, context: EventContext) => context, - }); + }; const cf = makeCloudFunction(args); const test: Event = { context: { @@ -206,10 +206,11 @@ describe('makeCloudFunction', () => { }); it('should throw error when context.params accessed in handler environment', () => { - const args: any = _.assign({}, cloudFunctionArgs, { + const args: any = { + ...cloudFunctionArgs, handler: (data: any, context: EventContext) => context, triggerResource: () => null, - }); + }; const cf = makeCloudFunction(args); const test: Event = { context: { @@ -429,7 +430,9 @@ describe('Change', () => { it('should apply the customizer function to `before` and `after`', () => { function customizer(input: any) { - _.set(input, 'another', 'value'); + if (input) { + input.another = 'value'; + } return input as T; } const created = Change.fromJSON( diff --git a/spec/v1/providers/database.spec.ts b/spec/v1/providers/database.spec.ts index 30d24ea3c..f044e2ca2 100644 --- a/spec/v1/providers/database.spec.ts +++ b/spec/v1/providers/database.spec.ts @@ -21,7 +21,7 @@ // SOFTWARE. import { expect } from 'chai'; -import { apps as appsNamespace } from '../../../src/apps'; +import { getApp, setApp } from '../../../src/common/app'; import * as config from '../../../src/config'; import * as functions from '../../../src/index'; import * as database from '../../../src/providers/database'; @@ -59,12 +59,11 @@ describe('Database Functions', () => { (config as any).firebaseConfigCache = { databaseURL: 'https://subdomain.apse.firebasedatabase.app', }; - appsNamespace.init(); }); after(() => { (config as any).firebaseConfigCache = null; - delete appsNamespace.singleton; + setApp(undefined); }); it('should allow both region and runtime options to be set', () => { @@ -586,14 +585,13 @@ describe('Database Functions', () => { describe('DataSnapshot', () => { let subject: any; - const apps = new appsNamespace.Apps(); const populate = (data: any) => { const [instance, path] = database.extractInstanceAndPath( 'projects/_/instances/other-subdomain/refs/foo', 'firebaseio-staging.com' ); - subject = new database.DataSnapshot(data, path, apps.admin, instance); + subject = new database.DataSnapshot(data, path, getApp(), instance); }; describe('#ref: firebase.database.Reference', () => { @@ -903,7 +901,7 @@ describe('Database Functions', () => { const snapshot = new database.DataSnapshot( null, path, - apps.admin, + getApp(), instance ); expect(snapshot.key).to.be.null; diff --git a/spec/v1/providers/firestore.spec.ts b/spec/v1/providers/firestore.spec.ts index 3f9f07fbe..49fae4fef 100644 --- a/spec/v1/providers/firestore.spec.ts +++ b/spec/v1/providers/firestore.spec.ts @@ -21,8 +21,7 @@ // SOFTWARE. import { expect } from 'chai'; -import * as admin from 'firebase-admin'; -import * as _ from 'lodash'; +import { Timestamp } from 'firebase-admin/firestore'; import * as functions from '../../../src/index'; import * as firestore from '../../../src/providers/firestore'; @@ -41,18 +40,16 @@ describe('Firestore Functions', () => { context = context || {}; return { data, - context: _.merge( - { - eventId: '123', - timestamp: '2018-07-03T00:49:04.264Z', - eventType: 'google.firestore.document.create', - resource: { - name: 'projects/myproj/databases/(default)/documents/tests/test1', - service: 'service', - }, + context: { + eventId: '123', + timestamp: '2018-07-03T00:49:04.264Z', + eventType: 'google.firestore.document.create', + resource: { + name: 'projects/myproj/databases/(default)/documents/tests/test1', + service: 'service', }, - context - ), + ...context, + }, }; } @@ -521,7 +518,7 @@ describe('Firestore Functions', () => { value: raw, }) ); - expect(_.get(snapshot.data(), 'referenceVal').path).to.equal('doc1/id'); + expect(snapshot.data()?.referenceVal?.path).to.equal('doc1/id'); }); it('should parse timestamp values with precision to the millisecond', () => { @@ -536,7 +533,7 @@ describe('Firestore Functions', () => { }) ); expect(snapshot.data()).to.deep.equal({ - timestampVal: admin.firestore.Timestamp.fromDate( + timestampVal: Timestamp.fromDate( new Date('2017-06-13T00:58:40.349Z') ), }); @@ -554,9 +551,7 @@ describe('Firestore Functions', () => { }) ); expect(snapshot.data()).to.deep.equal({ - timestampVal: admin.firestore.Timestamp.fromDate( - new Date('2017-06-13T00:58:40Z') - ), + timestampVal: Timestamp.fromDate(new Date('2017-06-13T00:58:40Z')), }); }); diff --git a/src/apps.ts b/src/apps.ts deleted file mode 100644 index 163cd4795..000000000 --- a/src/apps.ts +++ /dev/null @@ -1,134 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 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. - -import * as firebase from 'firebase-admin'; -import * as _ from 'lodash'; -import { firebaseConfig } from './config'; - -export function apps(): apps.Apps { - if (typeof apps.singleton === 'undefined') { - apps.init(); - } - return apps.singleton; -} - -export namespace apps { - /** @hidden */ - export const garbageCollectionInterval = 2 * 60 * 1000; - - /** @hidden */ - export function delay(delay: number) { - return new Promise((resolve) => { - setTimeout(resolve, delay); - }); - } - - export let singleton: apps.Apps; - - export let init = () => (singleton = new Apps()); - - export interface AuthMode { - admin: boolean; - variable?: any; - } - - /** @hidden */ - export interface RefCounter { - [appName: string]: number; - } - - export class Apps { - private _refCounter: RefCounter; - private _emulatedAdminApp?: firebase.app.App; - - constructor() { - this._refCounter = {}; - } - - _appAlive(appName: string): boolean { - try { - const app = firebase.app(appName); - return !_.get(app, 'isDeleted_'); - } catch (e) { - return false; - } - } - - _destroyApp(appName: string) { - if (!this._appAlive(appName)) { - return; - } - firebase - .app(appName) - .delete() - .catch(_.noop); - } - - retain() { - const increment = (n?: number) => { - return (n || 0) + 1; - }; - // Increment counter for admin because function might use event.data.ref - _.update(this._refCounter, '__admin__', increment); - } - - release() { - const decrement = (n: number) => { - return n - 1; - }; - return delay(garbageCollectionInterval).then(() => { - _.update(this._refCounter, '__admin__', decrement); - _.forEach(this._refCounter, (count, key) => { - if (count <= 0) { - this._destroyApp(key); - } - }); - }); - } - - get admin(): firebase.app.App { - if (this._emulatedAdminApp) { - return this._emulatedAdminApp; - } - - if (this._appAlive('__admin__')) { - return firebase.app('__admin__'); - } - return firebase.initializeApp(this.firebaseArgs, '__admin__'); - } - - /** - * This function allows the Firebase Emulator Suite to override the FirebaseApp instance - * used by the Firebase Functions SDK. Developers should never call this function for - * other purposes. - */ - setEmulatedAdminApp(app: firebase.app.App) { - this._emulatedAdminApp = app; - } - - private get firebaseArgs() { - return _.assign({}, firebaseConfig(), { - credential: firebase.credential.applicationDefault(), - }); - } - } -} diff --git a/src/cloud-functions.ts b/src/cloud-functions.ts index a362230fb..07c117d4a 100644 --- a/src/cloud-functions.ts +++ b/src/cloud-functions.ts @@ -21,7 +21,6 @@ // SOFTWARE. import { Request, Response } from 'express'; -import * as _ from 'lodash'; import { DEFAULT_FAILURE_POLICY, DeploymentOptions, @@ -43,9 +42,10 @@ import { ManifestEndpoint, ManifestRequiredAPI } from './runtime/manifest'; const WILDCARD_REGEX = new RegExp('{[^/{}]*}', 'g'); /** - * @hidden - * * Wire format for an event. + + * @hidden + * @alpha */ export interface Event { context: { @@ -54,6 +54,13 @@ export interface Event { eventType: string; resource: Resource; domain?: string; + auth?: { + variable?: { + uid?: string; + token?: string; + }; + admin: boolean; + }; }; data: any; } @@ -231,14 +238,21 @@ export namespace Change { const before = { ...after }; const masks = fieldMask.split(','); - masks.forEach((mask) => { - const val = _.get(sparseBefore, mask); + for (const mask of masks) { + const parts = mask.split('.'); + const head = parts[0]; + const tail = parts.slice(1).join('.'); + if (parts.length > 1) { + before[head] = applyFieldMask(sparseBefore?.[head], after[head], tail); + continue; + } + const val = sparseBefore?.[head]; if (typeof val === 'undefined') { - _.unset(before, mask); + delete before[mask]; } else { - _.set(before, mask, val); + before[mask] = val; } - }); + } return before; } @@ -374,8 +388,6 @@ export interface MakeCloudFunctionArgs { /** @hidden */ export function makeCloudFunction({ - after = () => {}, - before = () => {}, contextOnlyHandler, dataConstructor = (raw: Event) => raw.data, eventType, @@ -426,8 +438,6 @@ export function makeCloudFunction({ context.params = context.params || _makeParams(context, triggerResource); } - before(event); - let promise; if (labels && labels['deployment-scheduled']) { // Scheduled function do not have meaningful data, so exclude it @@ -439,15 +449,7 @@ export function makeCloudFunction({ if (typeof promise === 'undefined') { warn('Function returned undefined, expected Promise or value'); } - return Promise.resolve(promise) - .then((result) => { - after(event); - return result; - }) - .catch((err) => { - after(event); - return Promise.reject(err); - }); + return Promise.resolve(promise); }; Object.defineProperty(cloudFunction, '__trigger', { @@ -456,14 +458,15 @@ export function makeCloudFunction({ return {}; } - const trigger: any = _.assign(optionsToTrigger(options), { + const trigger: any = { + ...optionsToTrigger(options), eventTrigger: { resource: triggerResource(), eventType: legacyEventType || provider + '.' + eventType, service, }, - }); - if (!_.isEmpty(labels)) { + }; + if (!!labels && Object.keys(labels).length) { trigger.labels = { ...trigger.labels, ...labels }; } return trigger; @@ -519,7 +522,7 @@ export function makeCloudFunction({ function _makeParams( context: EventContext, triggerResourceGetter: () => string -): { [option: string]: any } { +): Record { if (context.params) { // In unit testing, user may directly provide `context.params`. return context.params; @@ -531,14 +534,16 @@ function _makeParams( const triggerResource = triggerResourceGetter(); const wildcards = triggerResource.match(WILDCARD_REGEX); const params: { [option: string]: any } = {}; - if (wildcards) { - const triggerResourceParts = _.split(triggerResource, '/'); - const eventResourceParts = _.split(context.resource.name, '/'); - _.forEach(wildcards, (wildcard) => { + + // Note: some tests don't set context.resource.name + const eventResourceParts = context?.resource?.name?.split?.('/'); + if (wildcards && eventResourceParts) { + const triggerResourceParts = triggerResource.split('/'); + for (const wildcard of wildcards) { const wildcardNoBraces = wildcard.slice(1, -1); - const position = _.indexOf(triggerResourceParts, wildcard); + const position = triggerResourceParts.indexOf(wildcard); params[wildcardNoBraces] = eventResourceParts[position]; - }); + } } return params; } @@ -549,17 +554,17 @@ function _makeAuth(event: Event, authType: string) { return null; } return { - uid: _.get(event, 'context.auth.variable.uid'), - token: _.get(event, 'context.auth.variable.token'), + uid: event.context?.auth?.variable?.uid, + token: event.context?.auth?.variable?.token, }; } /** @hidden */ function _detectAuthType(event: Event) { - if (_.get(event, 'context.auth.admin')) { + if (event.context?.auth?.admin) { return 'ADMIN'; } - if (_.has(event, 'context.auth.variable')) { + if (event.context?.auth?.variable) { return 'USER'; } return 'UNAUTHENTICATED'; diff --git a/src/common/app.ts b/src/common/app.ts new file mode 100644 index 000000000..4fa55961f --- /dev/null +++ b/src/common/app.ts @@ -0,0 +1,69 @@ +// The MIT License (MIT) +// +// Copyright (c) 2017 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. + +import { + App, + applicationDefault, + deleteApp, + getApp as getAppNamed, + initializeApp, +} from 'firebase-admin/app'; +import { firebaseConfig } from '../config'; + +const APP_NAME = '__FIREBASE_FUNCTIONS_SDK__'; + +let cache: App; +export function getApp(): App { + if (typeof cache === 'undefined') { + try { + cache = getAppNamed(/* default */); + } catch {} + } + if (typeof cache === 'undefined') { + cache = initializeApp( + { + ...firebaseConfig(), + credential: applicationDefault(), + }, + APP_NAME + ); + } + return cache; +} + +/** + * This function allows the Firebase Emulator Suite to override the FirebaseApp instance + * used by the Firebase Functions SDK. Developers should never call this function for + * other purposes. + * N.B. For clarity for use in testing this name has no mention of emulation, but + * it must be exported from index as app.setEmulatedAdminApp or we break the emulator. + * We can remove this export when: + * A) We complete the new emulator and no longer depend on monkeypatching + * B) We tweak the CLI to look for different APIs to monkeypatch depending on versions. + * @alpha + */ +export function setApp(app?: App) { + if (cache?.name === APP_NAME) { + deleteApp(cache); + } + cache = app; +} diff --git a/src/common/providers/database.ts b/src/common/providers/database.ts index f14ce8b1d..d7fc84449 100644 --- a/src/common/providers/database.ts +++ b/src/common/providers/database.ts @@ -20,18 +20,19 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import * as firebase from 'firebase-admin'; +import { App } from 'firebase-admin/app'; +import * as database from 'firebase-admin/database'; import { firebaseConfig } from '../../config'; import { joinPath, pathParts } from '../../utilities/path'; /** * Interface representing a Firebase Realtime database data snapshot. */ -export class DataSnapshot implements firebase.database.DataSnapshot { +export class DataSnapshot implements database.DataSnapshot { public instance: string; /** @hidden */ - private _ref: firebase.database.Reference; + private _ref: database.Reference; /** @hidden */ private _path: string; @@ -45,7 +46,7 @@ export class DataSnapshot implements firebase.database.DataSnapshot { constructor( data: any, path?: string, // path is undefined for the database root - private app?: firebase.app.App, + private app?: App, instance?: string ) { const config = firebaseConfig(); @@ -75,7 +76,7 @@ export class DataSnapshot implements firebase.database.DataSnapshot { * to the database location where the triggering write occurred. Has * full read and write access. */ - get ref(): firebase.database.Reference { + get ref(): database.Reference { if (!this.app) { // may be unpopulated in user's unit tests throw new Error( @@ -84,7 +85,13 @@ export class DataSnapshot implements firebase.database.DataSnapshot { ); } if (!this._ref) { - this._ref = this.app.database(this.instance).ref(this._fullPath()); + let db: database.Database; + if (this.instance) { + db = database.getDatabaseWithUrl(this.instance, this.app); + } else { + db = database.getDatabase(this.app); + } + this._ref = db.ref(this._fullPath()); } return this._ref; } diff --git a/src/common/providers/https.ts b/src/common/providers/https.ts index dc7de3c2b..85a760298 100644 --- a/src/common/providers/https.ts +++ b/src/common/providers/https.ts @@ -23,13 +23,14 @@ import * as cors from 'cors'; import * as express from 'express'; import { DecodedAppCheckToken } from 'firebase-admin/app-check'; -import { DecodedIdToken } from 'firebase-admin/auth'; import * as logger from '../../logger'; // TODO(inlined): Decide whether we want to un-version apps or whether we want a // different strategy -import { apps } from '../../apps'; +import { getAppCheck } from 'firebase-admin/app-check'; +import { DecodedIdToken, getAuth } from 'firebase-admin/auth'; +import { getApp } from '../app'; import { isDebugFeatureEnabled } from '../debug'; import { TaskContext } from './tasks'; @@ -591,9 +592,7 @@ export async function checkAuthToken( if (isDebugFeatureEnabled('skipTokenVerification')) { authToken = unsafeDecodeIdToken(idToken); } else { - authToken = await apps() - .admin.auth() - .verifyIdToken(idToken); + authToken = await getAuth(getApp()).verifyIdToken(idToken); } ctx.auth = { uid: authToken.uid, @@ -622,9 +621,7 @@ async function checkAppCheckToken( const decodedToken = unsafeDecodeAppCheckToken(appCheck); appCheckData = { appId: decodedToken.app_id, token: decodedToken }; } else { - appCheckData = await apps() - .admin.appCheck() - .verifyToken(appCheck); + appCheckData = await getAppCheck(getApp()).verifyToken(appCheck); } ctx.app = appCheckData; return 'VALID'; diff --git a/src/common/providers/identity.ts b/src/common/providers/identity.ts index 948c73ce9..0650d9266 100644 --- a/src/common/providers/identity.ts +++ b/src/common/providers/identity.ts @@ -21,10 +21,10 @@ // SOFTWARE. import * as express from 'express'; -import * as firebase from 'firebase-admin'; +import * as auth from 'firebase-admin/auth'; import { logger } from '../..'; -import { apps } from '../../apps'; import { EventContext } from '../../cloud-functions'; +import { getApp } from '../app'; import { isDebugFeatureEnabled } from '../debug'; import { HttpsError, unsafeDecodeToken } from './https'; @@ -66,17 +66,17 @@ const EVENT_MAPPING: Record = { * The UserRecord passed to Cloud Functions is the same UserRecord that is returned by the Firebase Admin * SDK. */ -export type UserRecord = firebase.auth.UserRecord; +export type UserRecord = auth.UserRecord; /** * UserInfo that is part of the UserRecord */ -export type UserInfo = firebase.auth.UserInfo; +export type UserInfo = auth.UserInfo; /** * Helper class to create the user metadata in a UserRecord object */ -export class UserRecordMetadata implements firebase.auth.UserMetadata { +export class UserRecordMetadata implements auth.UserMetadata { constructor(public creationTime: string, public lastSignInTime: string) {} /** Returns a plain JavaScript object with the properties of UserRecordMetadata. */ @@ -825,7 +825,7 @@ export function wrapHandler( throw new HttpsError('invalid-argument', 'Bad Request'); } - if (!apps().admin.auth()._verifyAuthBlockingToken) { + if (!auth.getAuth(getApp())._verifyAuthBlockingToken) { throw new Error( 'Cannot validate Auth Blocking token. Please update Firebase Admin SDK to >= v10.1.0' ); @@ -835,8 +835,8 @@ export function wrapHandler( 'skipTokenVerification' ) ? unsafeDecodeAuthBlockingToken(req.body.data.jwt) - : await apps() - .admin.auth() + : await auth + .getAuth(getApp()) ._verifyAuthBlockingToken(req.body.data.jwt); const authUserRecord = parseAuthUserRecord(decodedPayload.user_record); diff --git a/src/common/providers/tasks.ts b/src/common/providers/tasks.ts index d84f7a585..a7e1b2a2a 100644 --- a/src/common/providers/tasks.ts +++ b/src/common/providers/tasks.ts @@ -21,7 +21,7 @@ // SOFTWARE. import * as express from 'express'; -import * as firebase from 'firebase-admin'; +import { DecodedIdToken } from 'firebase-admin/auth'; import * as logger from '../../logger'; import * as https from './https'; @@ -77,7 +77,7 @@ export interface RateLimits { /** Metadata about the authorization used to invoke a function. */ export interface AuthData { uid: string; - token: firebase.auth.DecodedIdToken; + token: DecodedIdToken; } /** Metadata about a call to a Task Queue function. */ diff --git a/src/function-builder.ts b/src/function-builder.ts index 0c313c637..eec10f65f 100644 --- a/src/function-builder.ts +++ b/src/function-builder.ts @@ -21,7 +21,6 @@ // SOFTWARE. import * as express from 'express'; -import * as _ from 'lodash'; import { CloudFunction, EventContext } from './cloud-functions'; import { @@ -53,7 +52,7 @@ import * as testLab from './providers/testLab'; function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { if ( runtimeOptions.memory && - !_.includes(VALID_MEMORY_OPTIONS, runtimeOptions.memory) + !VALID_MEMORY_OPTIONS.includes(runtimeOptions.memory) ) { throw new Error( `The only valid memory allocation values are: ${VALID_MEMORY_OPTIONS.join( @@ -72,7 +71,7 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { if ( runtimeOptions.ingressSettings && - !_.includes(INGRESS_SETTINGS_OPTIONS, runtimeOptions.ingressSettings) + !INGRESS_SETTINGS_OPTIONS.includes(runtimeOptions.ingressSettings) ) { throw new Error( `The only valid ingressSettings values are: ${INGRESS_SETTINGS_OPTIONS.join( @@ -83,8 +82,7 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { if ( runtimeOptions.vpcConnectorEgressSettings && - !_.includes( - VPC_EGRESS_SETTINGS_OPTIONS, + !VPC_EGRESS_SETTINGS_OPTIONS.includes( runtimeOptions.vpcConnectorEgressSettings ) ) { @@ -95,28 +93,11 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { ); } - if (runtimeOptions.failurePolicy !== undefined) { - if ( - _.isBoolean(runtimeOptions.failurePolicy) === false && - _.isObjectLike(runtimeOptions.failurePolicy) === false - ) { - throw new Error(`failurePolicy must be a boolean or an object.`); - } - - if (typeof runtimeOptions.failurePolicy === 'object') { - if ( - _.isObjectLike(runtimeOptions.failurePolicy.retry) === false || - _.isEmpty(runtimeOptions.failurePolicy.retry) === false - ) { - throw new Error('failurePolicy.retry must be an empty object.'); - } - } - } - + validateFailurePolicy(runtimeOptions.failurePolicy); if ( runtimeOptions.serviceAccount && runtimeOptions.serviceAccount !== 'default' && - !_.includes(runtimeOptions.serviceAccount, '@') + !runtimeOptions.serviceAccount.includes('@') ) { throw new Error( `serviceAccount must be set to 'default', a service account email, or '{serviceAccountName}@'` @@ -252,6 +233,20 @@ function assertRuntimeOptionsValid(runtimeOptions: RuntimeOptions): boolean { return true; } +function validateFailurePolicy(policy: any) { + if (typeof policy === 'boolean' || typeof policy === 'undefined') { + return; + } + if (typeof policy !== 'object') { + throw new Error(`failurePolicy must be a boolean or an object.`); + } + + const retry = policy.retry; + if (typeof retry !== 'object' || Object.keys(retry).length) { + throw new Error('failurePolicy.retry must be an empty object.'); + } +} + /** * Assert regions specified are valid. * @param regions list of regions. @@ -341,7 +336,10 @@ export class FunctionBuilder { */ runWith(runtimeOptions: RuntimeOptions): FunctionBuilder { if (assertRuntimeOptionsValid(runtimeOptions)) { - this.options = _.assign(this.options, runtimeOptions); + this.options = { + ...this.options, + ...runtimeOptions, + }; return this; } } diff --git a/src/handler-builder.ts b/src/handler-builder.ts index c976bf8e6..dcce26bcc 100644 --- a/src/handler-builder.ts +++ b/src/handler-builder.ts @@ -22,7 +22,6 @@ import * as express from 'express'; -import { apps } from './apps'; import { CloudFunction, EventContext, HttpsFunction } from './cloud-functions'; import * as analytics from './providers/analytics'; import * as auth from './providers/auth'; @@ -158,12 +157,12 @@ export class HandlerBuilder { get instance() { return { get ref() { - return new database.RefBuilder(apps(), () => null, {}); + return new database.RefBuilder(() => null, {}); }, }; }, get ref() { - return new database.RefBuilder(apps(), () => null, {}); + return new database.RefBuilder(() => null, {}); }, }; } diff --git a/src/index.ts b/src/index.ts index a77ba3ff9..e7b23b834 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,16 +32,13 @@ import * as storage from './providers/storage'; import * as tasks from './providers/tasks'; import * as testLab from './providers/testLab'; -import * as apps from './apps'; +import { setApp as setEmulatedAdminApp } from './common/app'; import { handler } from './handler-builder'; import * as logger from './logger'; import { setup } from './setup'; -const app = apps.apps(); - export { analytics, - app, auth, database, firestore, @@ -55,6 +52,8 @@ export { logger, }; +export const app = { setEmulatedAdminApp }; + // Exported root types: export * from './cloud-functions'; export * from './config'; diff --git a/src/providers/analytics.ts b/src/providers/analytics.ts index 2d57d6f5e..f5d68bc8c 100644 --- a/src/providers/analytics.ts +++ b/src/providers/analytics.ts @@ -20,8 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import * as _ from 'lodash'; - import { CloudFunction, Event, @@ -143,7 +141,7 @@ export class AnalyticsEvent { // If there's an eventDim, there'll always be exactly one. const eventDim = wireFormat.eventDim[0]; copyField(eventDim, this, 'name'); - copyField(eventDim, this, 'params', (p) => _.mapValues(p, unwrapValue)); + copyField(eventDim, this, 'params', (p) => mapKeys(p, unwrapValue)); copyFieldTo(eventDim, this, 'valueInUsd', 'valueInUSD'); copyFieldTo(eventDim, this, 'date', 'reportingDate'); copyTimestampToString(eventDim, this, 'timestampMicros', 'logTime'); @@ -218,10 +216,19 @@ export class UserDimensions { 'firstOpenTime' ); this.userProperties = {}; // With no entries in the wire format, present an empty (as opposed to absent) map. - copyField(wireFormat, this, 'userProperties', (r) => - _.mapValues(r, (p) => new UserPropertyValue(p)) + copyField(wireFormat, this, 'userProperties', (r) => { + const entries = Object.entries(r).map(([k, v]) => [ + k, + new UserPropertyValue(v), + ]); + return Object.fromEntries(entries); + }); + copyField( + wireFormat, + this, + 'bundleInfo', + (r) => new ExportBundleInfo(r) as any ); - copyField(wireFormat, this, 'bundleInfo', (r) => new ExportBundleInfo(r)); // BUG(36000368) Remove when no longer necessary /* tslint:disable:no-string-literal */ @@ -242,7 +249,7 @@ export class UserPropertyValue { /** @hidden */ constructor(wireFormat: any) { - copyField(wireFormat, this, 'value', unwrapValueAsString); + copyField(wireFormat, this, 'value', unwrapValueAsString as any); copyTimestampToString(wireFormat, this, 'setTimestampUsec', 'setTime'); } } @@ -418,35 +425,66 @@ export class ExportBundleInfo { } /** @hidden */ -function copyFieldTo( - from: any, - to: T, - fromField: string, - toField: K, - transform: (val: any) => T[K] = _.identity +function copyFieldTo< + From extends object, + FromKey extends keyof From, + To extends object, + ToKey extends keyof To +>( + from: From, + to: To, + fromField: FromKey, + toField: ToKey, + transform?: (val: Required[FromKey]) => Required[ToKey] ): void { - if (from[fromField] !== undefined) { + if (typeof from[fromField] === 'undefined') { + return; + } + if (transform) { to[toField] = transform(from[fromField]); + return; } + to[toField] = from[fromField] as any; } /** @hidden */ -function copyField( - from: any, - to: T, - field: K, - transform: (val: any) => T[K] = _.identity +function copyField< + From extends object, + To extends Object, + Key extends keyof From & keyof To +>( + from: From, + to: To, + field: Key, + transform: (val: Required[Key]) => Required[Key] = (from) => + from as any ): void { - copyFieldTo(from, to, field as string, field, transform); + copyFieldTo(from, to, field, field, transform); } /** @hidden */ -function copyFields(from: any, to: T, fields: K[]): void { +function copyFields< + From extends object, + To extends object, + Key extends keyof From & keyof To +>(from: From, to: To, fields: Key[]): void { for (const field of fields) { copyField(from, to, field); } } +type TransformedObject< + Obj extends Object, + Transform extends (key: keyof Obj) => any +> = { [key in keyof Obj]: ReturnType }; +function mapKeys any>( + obj: Obj, + transform: Transform +): TransformedObject { + const entries = Object.entries(obj).map(([k, v]) => [k, transform(v)]); + return Object.fromEntries(entries); +} + // The incoming payload will have fields like: // { // 'myInt': { @@ -478,8 +516,8 @@ function copyFields(from: any, to: T, fields: K[]): void { // 'unwrapValue' method just below. /** @hidden */ function unwrapValueAsString(wrapped: any): string { - const key: string = _.keys(wrapped)[0]; - return _.toString(wrapped[key]); + const key: string = Object.keys(wrapped)[0]; + return wrapped[key].toString(); } // Ditto as the method above, but returning the values in the idiomatic JavaScript type (string for strings, @@ -500,9 +538,9 @@ const xValueNumberFields = ['intValue', 'floatValue', 'doubleValue']; /** @hidden */ function unwrapValue(wrapped: any): any { - const key: string = _.keys(wrapped)[0]; + const key: string = Object.keys(wrapped)[0]; const value: string = unwrapValueAsString(wrapped); - return _.includes(xValueNumberFields, key) ? _.toNumber(value) : value; + return xValueNumberFields.includes(key) ? Number(value) : value; } // The JSON payload delivers timestamp fields as strings of timestamps denoted in microseconds. @@ -516,7 +554,7 @@ function copyTimestampToMillis( toName: K ) { if (from[fromName] !== undefined) { - to[toName] = _.round(from[fromName] / 1000) as any; + to[toName] = Math.round(from[fromName] / 1000) as any; } } diff --git a/src/providers/database.ts b/src/providers/database.ts index 5b7dc59f5..8dba83ffc 100644 --- a/src/providers/database.ts +++ b/src/providers/database.ts @@ -20,7 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { apps } from '../apps'; import { Change, CloudFunction, @@ -28,6 +27,7 @@ import { EventContext, makeCloudFunction, } from '../cloud-functions'; +import { getApp } from '../common/app'; import { DataSnapshot } from '../common/providers/database'; import { firebaseConfig } from '../config'; import { DeploymentOptions } from '../function-configuration'; @@ -117,7 +117,6 @@ export class InstanceBuilder { ref(path: string): RefBuilder { const normalized = normalizePath(path); return new RefBuilder( - apps(), () => `projects/_/instances/${this.instance}/refs/${normalized}`, this.options ); @@ -161,7 +160,7 @@ export function _refWithOptions( return `projects/_/instances/${instance}/refs/${normalized}`; }; - return new RefBuilder(apps(), resourceGetter, options); + return new RefBuilder(resourceGetter, options); } /** @@ -172,7 +171,6 @@ export function _refWithOptions( export class RefBuilder { /** @hidden */ constructor( - private apps: apps.Apps, private triggerResource: () => string, private options: DeploymentOptions ) {} @@ -231,12 +229,7 @@ export class RefBuilder { raw.context.resource.name, raw.context.domain ); - return new DataSnapshot( - raw.data.delta, - path, - this.apps.admin, - dbInstance - ); + return new DataSnapshot(raw.data.delta, path, getApp(), dbInstance); }; return this.onOperation(handler, 'ref.create', dataConstructor); } @@ -260,7 +253,7 @@ export class RefBuilder { raw.context.resource.name, raw.context.domain ); - return new DataSnapshot(raw.data.data, path, this.apps.admin, dbInstance); + return new DataSnapshot(raw.data.data, path, getApp(), dbInstance); }; return this.onOperation(handler, 'ref.delete', dataConstructor); } @@ -278,8 +271,6 @@ export class RefBuilder { legacyEventType: `providers/${provider}/eventTypes/${eventType}`, triggerResource: this.triggerResource, dataConstructor, - before: (event) => this.apps.retain(), - after: (event) => this.apps.release(), options: this.options, }); } @@ -289,16 +280,11 @@ export class RefBuilder { raw.context.resource.name, raw.context.domain ); - const before = new DataSnapshot( - raw.data.data, - path, - this.apps.admin, - dbInstance - ); + const before = new DataSnapshot(raw.data.data, path, getApp(), dbInstance); const after = new DataSnapshot( applyChange(raw.data.data, raw.data.delta), path, - this.apps.admin, + getApp(), dbInstance ); return { diff --git a/src/providers/firestore.ts b/src/providers/firestore.ts index 620040d2b..e159d62bf 100644 --- a/src/providers/firestore.ts +++ b/src/providers/firestore.ts @@ -20,11 +20,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import * as firebase from 'firebase-admin'; -import * as _ from 'lodash'; +import * as firestore from 'firebase-admin/firestore'; import { posix } from 'path'; -import { apps } from '../apps'; import { Change, CloudFunction, @@ -32,6 +30,7 @@ import { EventContext, makeCloudFunction, } from '../cloud-functions'; +import { getApp } from '../common/app'; import { dateToTimestampProto } from '../encoder'; import { DeploymentOptions } from '../function-configuration'; import * as logger from '../logger'; @@ -43,8 +42,8 @@ export const service = 'firestore.googleapis.com'; /** @hidden */ export const defaultDatabase = '(default)'; let firestoreInstance: any; -export type DocumentSnapshot = firebase.firestore.DocumentSnapshot; -export type QueryDocumentSnapshot = firebase.firestore.QueryDocumentSnapshot; +export type DocumentSnapshot = firestore.DocumentSnapshot; +export type QueryDocumentSnapshot = firestore.QueryDocumentSnapshot; /** * Select the Firestore document to listen to for events. @@ -130,19 +129,20 @@ export class NamespaceBuilder { } function _getValueProto(data: any, resource: string, valueFieldName: string) { - if (_.isEmpty(_.get(data, valueFieldName))) { + const value = data?.[valueFieldName]; + if ( + typeof value === 'undefined' || + value === null || + (typeof value === 'object' && !Object.keys(value).length) + ) { // Firestore#snapshot_ takes resource string instead of proto for a non-existent snapshot return resource; } const proto = { - fields: _.get(data, [valueFieldName, 'fields'], {}), - createTime: dateToTimestampProto( - _.get(data, [valueFieldName, 'createTime']) - ), - updateTime: dateToTimestampProto( - _.get(data, [valueFieldName, 'updateTime']) - ), - name: _.get(data, [valueFieldName, 'name'], resource), + fields: value?.fields || {}, + createTime: dateToTimestampProto(value?.createTime), + updateTime: dateToTimestampProto(value?.updateTime), + name: value?.name || resource, }; return proto; } @@ -150,7 +150,7 @@ function _getValueProto(data: any, resource: string, valueFieldName: string) { /** @hidden */ export function snapshotConstructor(event: Event): DocumentSnapshot { if (!firestoreInstance) { - firestoreInstance = firebase.firestore(apps().admin); + firestoreInstance = firestore.getFirestore(getApp()); } const valueProto = _getValueProto( event.data, @@ -158,8 +158,7 @@ export function snapshotConstructor(event: Event): DocumentSnapshot { 'value' ); let timeString = - _.get(event, 'data.value.readTime') ?? - _.get(event, 'data.value.updateTime'); + event?.data?.value?.readTime ?? event?.data?.value?.updateTime; if (!timeString) { logger.warn('Snapshot has no readTime. Using now()'); @@ -174,16 +173,14 @@ export function snapshotConstructor(event: Event): DocumentSnapshot { // TODO remove this function when wire format changes to new format export function beforeSnapshotConstructor(event: Event): DocumentSnapshot { if (!firestoreInstance) { - firestoreInstance = firebase.firestore(apps().admin); + firestoreInstance = firestore.getFirestore(getApp()); } const oldValueProto = _getValueProto( event.data, event.context.resource.name, 'oldValue' ); - const oldReadTime = dateToTimestampProto( - _.get(event, 'data.oldValue.readTime') - ); + const oldReadTime = dateToTimestampProto(event?.data?.oldValue?.readTime); return firestoreInstance.snapshot_(oldValueProto, oldReadTime, 'json'); } diff --git a/src/providers/remoteConfig.ts b/src/providers/remoteConfig.ts index f15716c17..9cf54d686 100644 --- a/src/providers/remoteConfig.ts +++ b/src/providers/remoteConfig.ts @@ -20,8 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import * as _ from 'lodash'; - import { CloudFunction, EventContext, diff --git a/src/providers/testLab.ts b/src/providers/testLab.ts index 86398c5c9..e56429de2 100644 --- a/src/providers/testLab.ts +++ b/src/providers/testLab.ts @@ -20,8 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import * as _ from 'lodash'; - import { CloudFunction, Event, @@ -129,12 +127,15 @@ export class ClientInfo { details: { [key: string]: string }; /** @internal */ - constructor(data?: any) { - this.name = _.get(data, 'name', ''); + constructor(data?: { + name: string; + clientInfoDetails?: Array<{ key: string; value?: string }>; + }) { + this.name = data?.name || ''; this.details = {}; - _.forEach(_.get(data, 'clientInfoDetails'), (detail: any) => { + for (const detail of data?.clientInfoDetails || []) { this.details[detail.key] = detail.value || ''; - }); + } } } @@ -157,13 +158,10 @@ export class ResultStorage { /** @internal */ constructor(data?: any) { - this.gcsPath = _.get(data, 'googleCloudStorage.gcsPath'); - this.toolResultsHistoryId = _.get(data, 'toolResultsHistory.historyId'); - this.toolResultsExecutionId = _.get( - data, - 'toolResultsExecution.executionId' - ); - this.resultsUrl = _.get(data, 'resultsUrl'); + this.gcsPath = data?.googleCloudStorage?.gcsPath; + this.toolResultsHistoryId = data?.toolResultsHistory?.historyId; + this.toolResultsExecutionId = data?.toolResultsExecution?.executionId; + this.resultsUrl = data?.resultsUrl; } } diff --git a/src/utils.ts b/src/utils.ts index e41b1e1fb..2096607e2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -20,25 +20,36 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -/** @hidden */ -import * as _ from 'lodash'; +function isObject(obj: any): boolean { + return typeof obj === 'object' && !!obj; +} +/** @hidden */ export function applyChange(src: any, dest: any) { // if not mergeable, don't merge - if (!_.isPlainObject(dest) || !_.isPlainObject(src)) { + if (!isObject(dest) || !isObject(src)) { return dest; } - return pruneNulls(_.merge({}, src, dest)); + return merge(src, dest); } -export function pruneNulls(obj: any) { - for (const key in obj) { - if (obj[key] === null) { - delete obj[key]; - } else if (_.isPlainObject(obj[key])) { - pruneNulls(obj[key]); +function merge( + src: Record, + dest: Record +): Record { + const res: Record = {}; + const keys = new Set([...Object.keys(src), ...Object.keys(dest)]); + + for (const key of keys.values()) { + if (key in dest) { + if (dest[key] === null) { + continue; + } + res[key] = applyChange(src[key], dest[key]); + } else if (src[key] !== null) { + res[key] = src[key]; } } - return obj; + return res; } diff --git a/src/v2/providers/database.ts b/src/v2/providers/database.ts index e0b410422..372a949e8 100644 --- a/src/v2/providers/database.ts +++ b/src/v2/providers/database.ts @@ -20,8 +20,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { apps } from '../../apps'; import { Change } from '../../cloud-functions'; +import { getApp } from '../../common/app'; import { DataSnapshot } from '../../common/providers/database'; import { ManifestEndpoint } from '../../runtime/manifest'; import { normalizePath } from '../../utilities/path'; @@ -274,7 +274,7 @@ function makeDatabaseEvent( instance: string, params: Record ): DatabaseEvent { - const snapshot = new DataSnapshot(data, event.ref, apps().admin, instance); + const snapshot = new DataSnapshot(data, event.ref, getApp(), instance); const databaseEvent: DatabaseEvent = { ...event, firebaseDatabaseHost: event.firebasedatabasehost, @@ -294,13 +294,13 @@ function makeChangedDatabaseEvent( const before = new DataSnapshot( event.data.data, event.ref, - apps().admin, + getApp(), instance ); const after = new DataSnapshot( applyChange(event.data.data, event.data.delta), event.ref, - apps().admin, + getApp(), instance ); const databaseEvent: DatabaseEvent> = { diff --git a/tsconfig.release.json b/tsconfig.release.json index b98955ee5..93bbefe3a 100644 --- a/tsconfig.release.json +++ b/tsconfig.release.json @@ -1,13 +1,13 @@ { "compilerOptions": { "declaration": true, - "lib": ["es2018"], + "lib": ["es2019"], "module": "commonjs", "noImplicitAny": false, "noUnusedLocals": true, "outDir": "lib", "stripInternal": true, - "target": "es2018", + "target": "es2019", "typeRoots": ["./node_modules/@types"] }, "files": [ From 7ff3abeb92034557ba531d4ed88cf6228c65f0dd Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Mon, 27 Jun 2022 15:49:10 -0700 Subject: [PATCH 07/63] Divide everything into v1, v2, and common (unexported). (#1149) * Divide everything into v1, v2, and common (unexported). Did some refactoring, like putting `firebaseConfig` into common. This means we have absolutely no dependencies on v1 in common or v2. Some files are left at the root because they were modified in other CLs that are outstanding and I want to linearize the changes to minimize conflicts. While working, I removed some legacy workarounds that should no longer apply. For example, we no longer need to load fireaseConfig from runtime config because all supported versions of the CLI set the FIREBASE_CONFIG environment variable. This meant we could remove all of setup.ts because all monkeypatches were for outdated runtimes. Since there is no longer an environment change between importing v1/index and a subpackage, I've gone ahead and exported the providers for v1 to minimize customer frustration with the v1 namespace. * Fix dependency conflicts * Lint fixes * Remove __trigger (#1150) * Remove __trigger * Lint fixes * Divide everything into v1, v2, and common (unexported). Did some refactoring, like putting `firebaseConfig` into common. This means we have absolutely no dependencies on v1 in common or v2. Some files are left at the root because they were modified in other CLs that are outstanding and I want to linearize the changes to minimize conflicts. While working, I removed some legacy workarounds that should no longer apply. For example, we no longer need to load fireaseConfig from runtime config because all supported versions of the CLI set the FIREBASE_CONFIG environment variable. This meant we could remove all of setup.ts because all monkeypatches were for outdated runtimes. Since there is no longer an environment change between importing v1/index and a subpackage, I've gone ahead and exported the providers for v1 to minimize customer frustration with the v1 namespace. * Fix dependency conflicts * Lint fixes * Remove __trigger (#1150) * Remove __trigger * Lint fixes * Move apps and utilities into common --- integration_test/run_tests.sh | 4 +- package-lock.json | 6751 ++++++++++++++++- package.json | 73 +- .../setup.spec.ts => common/config.spec.ts} | 62 +- .../utilities/path-pattern.spec.ts | 2 +- spec/{ => common}/utilities/path.spec.ts | 2 +- spec/fixtures/sources/commonjs-grouped/g1.js | 2 +- .../sources/commonjs-grouped/index.js | 4 +- .../sources/commonjs-main/functions.js | 4 +- spec/fixtures/sources/commonjs/index.js | 4 +- spec/runtime/loader.spec.ts | 2 +- spec/v1/cloud-functions.spec.ts | 22 +- spec/v1/config.spec.ts | 70 +- spec/v1/function-builder.spec.ts | 55 +- spec/v1/providers/analytics.spec.input.ts | 2 +- spec/v1/providers/analytics.spec.ts | 28 +- spec/v1/providers/auth.spec.ts | 98 +- spec/v1/providers/database.spec.ts | 100 +- spec/v1/providers/firestore.spec.ts | 54 +- spec/v1/providers/https.spec.ts | 21 +- spec/v1/providers/pubsub.spec.ts | 89 +- spec/v1/providers/remoteConfig.spec.ts | 19 +- spec/v1/providers/storage.spec.ts | 101 +- spec/v1/providers/tasks.spec.ts | 33 +- spec/v1/providers/testLab.spec.ts | 18 +- spec/v1/utils.spec.ts | 2 +- spec/v2/providers/database.spec.ts | 2 +- spec/v2/providers/fixtures.ts | 19 - spec/v2/providers/https.spec.ts | 65 +- spec/v2/providers/pubsub.spec.ts | 31 +- spec/v2/providers/storage.spec.ts | 281 +- spec/v2/providers/tasks.spec.ts | 35 +- src/common/app.ts | 2 +- src/common/config.ts | 60 + src/common/encoding.ts | 32 - src/common/providers/database.ts | 4 +- src/common/providers/identity.ts | 4 +- src/{ => common}/utilities/assertions.ts | 0 src/{ => common/utilities}/encoder.ts | 0 src/{ => common}/utilities/path-pattern.ts | 0 src/{ => common}/utilities/path.ts | 0 src/{ => common/utilities}/utils.ts | 0 src/setup.ts | 67 - src/{ => v1}/cloud-functions.ts | 140 +- src/{ => v1}/config.ts | 101 +- src/{ => v1}/function-builder.ts | 0 src/{ => v1}/function-configuration.ts | 4 - src/{ => v1}/handler-builder.ts | 3 - src/{ => v1}/index.ts | 7 +- src/{ => v1}/providers/analytics.ts | 0 src/{ => v1}/providers/auth.ts | 32 +- src/{ => v1}/providers/database.ts | 10 +- src/{ => v1}/providers/firestore.ts | 6 +- src/{ => v1}/providers/https.ts | 31 +- src/{ => v1}/providers/pubsub.ts | 0 src/{ => v1}/providers/remoteConfig.ts | 0 src/{ => v1}/providers/storage.ts | 2 +- src/{ => v1}/providers/tasks.ts | 27 +- src/{ => v1}/providers/testLab.ts | 0 src/v2/core.ts | 33 - src/v2/options.ts | 70 +- src/v2/providers/database.ts | 8 +- src/v2/providers/https.ts | 59 - src/v2/providers/identity.ts | 2 +- src/v2/providers/pubsub.ts | 23 - src/v2/providers/storage.ts | 25 +- src/v2/providers/tasks.ts | 32 - tsconfig.release.json | 2 +- 68 files changed, 7005 insertions(+), 1836 deletions(-) rename spec/{v1/setup.spec.ts => common/config.spec.ts} (50%) rename spec/{ => common}/utilities/path-pattern.spec.ts (98%) rename spec/{ => common}/utilities/path.spec.ts (90%) create mode 100644 src/common/config.ts rename src/{ => common}/utilities/assertions.ts (100%) rename src/{ => common/utilities}/encoder.ts (100%) rename src/{ => common}/utilities/path-pattern.ts (100%) rename src/{ => common}/utilities/path.ts (100%) rename src/{ => common/utilities}/utils.ts (100%) delete mode 100644 src/setup.ts rename src/{ => v1}/cloud-functions.ts (84%) rename src/{ => v1}/config.ts (53%) rename src/{ => v1}/function-builder.ts (100%) rename src/{ => v1}/function-configuration.ts (98%) rename src/{ => v1}/handler-builder.ts (99%) rename src/{ => v1}/index.ts (93%) rename src/{ => v1}/providers/analytics.ts (100%) rename src/{ => v1}/providers/auth.ts (95%) rename src/{ => v1}/providers/database.ts (97%) rename src/{ => v1}/providers/firestore.ts (98%) rename src/{ => v1}/providers/https.ts (84%) rename src/{ => v1}/providers/pubsub.ts (100%) rename src/{ => v1}/providers/remoteConfig.ts (100%) rename src/{ => v1}/providers/storage.ts (99%) rename src/{ => v1}/providers/tasks.ts (86%) rename src/{ => v1}/providers/testLab.ts (100%) diff --git a/integration_test/run_tests.sh b/integration_test/run_tests.sh index 4c8e51d24..d943a4e81 100755 --- a/integration_test/run_tests.sh +++ b/integration_test/run_tests.sh @@ -78,9 +78,9 @@ function deploy { ./functions/node_modules/.bin/tsc -p functions/ # Deploy functions, and security rules for database and Firestore. If the deploy fails, retry twice if [[ "${TOKEN}" == "" ]]; then - for i in 1 2 3; do firebase deploy --project="${PROJECT_ID}" --only functions,database,firestore && break; done + for i in 1 2 3; do firebase deploy --project="${PROJECT_ID}" --only functions:integration-tests,database,firestore && break; done else - for i in 1 2 3; do firebase deploy --project="${PROJECT_ID}" --token="${TOKEN}" --only functions,database,firestore && break; done + for i in 1 2 3; do firebase deploy --project="${PROJECT_ID}" --token="${TOKEN}" --only functions:integration-tests,database,firestore && break; done fi } diff --git a/package-lock.json b/package-lock.json index c11eebe69..c4d06b6a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,6519 @@ { "name": "firebase-functions", "version": "3.21.2", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "firebase-functions", + "version": "3.21.2", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.5", + "@types/express": "4.17.3", + "cors": "^2.8.5", + "express": "^4.17.1", + "lodash": "^4.17.14", + "node-fetch": "^2.6.7" + }, + "bin": { + "firebase-functions": "lib/bin/firebase-functions.js" + }, + "devDependencies": { + "@firebase/api-documenter": "^0.1.2", + "@microsoft/api-documenter": "^7.13.45", + "@microsoft/api-extractor": "^7.18.7", + "@types/chai": "^4.1.7", + "@types/chai-as-promised": "^7.1.0", + "@types/jsonwebtoken": "^8.3.2", + "@types/lodash": "^4.14.135", + "@types/mocha": "^5.2.7", + "@types/mock-require": "^2.0.0", + "@types/nock": "^10.0.3", + "@types/node": "^8.10.50", + "@types/node-fetch": "^3.0.3", + "@types/sinon": "^7.0.13", + "api-extractor-model-me": "^0.1.1", + "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", + "child-process-promise": "^2.2.1", + "firebase-admin": "^10.1.0", + "js-yaml": "^3.13.1", + "jsdom": "^16.2.1", + "jsonwebtoken": "^8.5.1", + "jwk-to-pem": "^2.0.5", + "mocha": "^6.1.4", + "mock-require": "^3.0.3", + "mz": "^2.7.0", + "nock": "^10.0.6", + "node-fetch": "^2.6.7", + "portfinder": "^1.0.28", + "prettier": "^1.18.2", + "semver": "^7.3.5", + "sinon": "^7.3.2", + "ts-node": "^10.4.0", + "tslint": "^5.18.0", + "tslint-config-prettier": "^1.18.0", + "tslint-no-unused-expression-chai": "^0.1.4", + "tslint-plugin-prettier": "^2.0.1", + "typedoc": "^0.22.17", + "typescript": "^4.6.3", + "yargs": "^15.3.1" + }, + "engines": { + "node": ">=14.10.0" + }, + "peerDependencies": { + "firebase-admin": "^10.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@firebase/api-documenter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@firebase/api-documenter/-/api-documenter-0.1.2.tgz", + "integrity": "sha512-aDofRZebqbMzrbo5WAi9f21qUTzhIub7yOszirik3AwujqOzcUr1F7lIFrI41686JD1Zw56lLL/B5EWZTwvVjA==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.12.24", + "@rushstack/node-core-library": "3.36.0", + "@rushstack/ts-command-line": "4.7.8", + "api-extractor-model-me": "0.1.1", + "colors": "~1.2.1", + "js-yaml": "4.0.0", + "resolve": "~1.17.0", + "tslib": "^2.1.0" + }, + "bin": { + "api-documenter-fire": "dist/start.js" + } + }, + "node_modules/@firebase/api-documenter/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/@firebase/api-documenter/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@firebase/api-documenter/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@firebase/app": { + "version": "0.7.26", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.7.26.tgz", + "integrity": "sha512-FmJ4uaUyazmOZZWJO9OviKfnw+lrwMPQbWBMutymSQT8Gx783Ddnhs5IdmfV0NeLrlGy4ZwfP6/+RJyy2wGDXw==", + "dev": true, + "peer": true, + "dependencies": { + "@firebase/component": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.6.1", + "idb": "7.0.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-compat": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.27.tgz", + "integrity": "sha512-0A5ENP/KK0Eev94qPuxaclfOE0oA6hyCVQTdi0ox1bPm+VzGGD/jXP6Bzw+IUmy33ChjP/639bm6Myh8AG4PwA==", + "dev": true, + "peer": true, + "dependencies": { + "@firebase/app": "0.7.26", + "@firebase/component": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.6.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-compat/node_modules/@firebase/component": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.15.tgz", + "integrity": "sha512-VRnZxmvtJmXupTPg37LxM0zdyMN54EXkmsFD4x5Bm4eZUay9VGnhfiGnE3m9Af/2hnURA2idIBN/23L6982iPQ==", + "dev": true, + "peer": true, + "dependencies": { + "@firebase/util": "1.6.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-compat/node_modules/@firebase/logger": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.3.tgz", + "integrity": "sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-compat/node_modules/@firebase/util": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.1.tgz", + "integrity": "sha512-+eDE6uG5GgvXYHbAzfP1mpJUX1VDBD+A8CjBeBoNAKAVAApMSDxDODqRcOq7NW7kFJXSUkMzDJWhnUIifX2R8w==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.7.0.tgz", + "integrity": "sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg==", + "dev": true + }, + "node_modules/@firebase/app/node_modules/@firebase/component": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.15.tgz", + "integrity": "sha512-VRnZxmvtJmXupTPg37LxM0zdyMN54EXkmsFD4x5Bm4eZUay9VGnhfiGnE3m9Af/2hnURA2idIBN/23L6982iPQ==", + "dev": true, + "peer": true, + "dependencies": { + "@firebase/util": "1.6.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app/node_modules/@firebase/logger": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.3.tgz", + "integrity": "sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app/node_modules/@firebase/util": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.1.tgz", + "integrity": "sha512-+eDE6uG5GgvXYHbAzfP1mpJUX1VDBD+A8CjBeBoNAKAVAApMSDxDODqRcOq7NW7kFJXSUkMzDJWhnUIifX2R8w==", + "dev": true, + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz", + "integrity": "sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==", + "dev": true, + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.13.tgz", + "integrity": "sha512-hxhJtpD8Ppf/VU2Rlos6KFCEV77TGIGD5bJlkPK1+B/WUe0mC6dTjW7KhZtXTc+qRBp9nFHWcsIORnT8liHP9w==", + "dev": true, + "dependencies": { + "@firebase/util": "1.5.2", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "0.12.8", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.12.8.tgz", + "integrity": "sha512-JBQVfFLzfhxlQbl4OU6ov9fdsddkytBQdtSSR49cz48homj38ccltAhK6seum+BI7f28cV2LFHF9672lcN+qxA==", + "dev": true, + "dependencies": { + "@firebase/auth-interop-types": "0.1.6", + "@firebase/component": "0.5.13", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.5.2", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.1.8.tgz", + "integrity": "sha512-dhXr5CSieBuKNdU96HgeewMQCT9EgOIkfF1GNy+iRrdl7BWLxmlKuvLfK319rmIytSs/vnCzcD9uqyxTeU/A3A==", + "dev": true, + "dependencies": { + "@firebase/component": "0.5.13", + "@firebase/database": "0.12.8", + "@firebase/database-types": "0.9.7", + "@firebase/logger": "0.3.2", + "@firebase/util": "1.5.2", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/database-types": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.7.tgz", + "integrity": "sha512-EFhgL89Fz6DY3kkB8TzdHvdu8XaqqvzcF2DLVOXEnQ3Ms7L755p5EO42LfxXoJqb9jKFvgLpFmKicyJG25WFWw==", + "dev": true, + "dependencies": { + "@firebase/app-types": "0.7.0", + "@firebase/util": "1.5.2" + } + }, + "node_modules/@firebase/logger": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.2.tgz", + "integrity": "sha512-lzLrcJp9QBWpo40OcOM9B8QEtBw2Fk1zOZQdvv+rWS6gKmhQBCEMc4SMABQfWdjsylBcDfniD1Q+fUX1dcBTXA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/util": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.5.2.tgz", + "integrity": "sha512-YvBH2UxFcdWG2HdFnhxZptPl2eVFlpOyTH66iDo13JPEYraWzWToZ5AMTtkyRHVmu7sssUpQlU9igy1KET7TOw==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@google-cloud/firestore": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-4.15.1.tgz", + "integrity": "sha512-2PWsCkEF1W02QbghSeRsNdYKN1qavrHBP3m72gPDMHQSYrGULOaTi7fSJquQmAtc4iPVB2/x6h80rdLHTATQtA==", + "dev": true, + "optional": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "functional-red-black-tree": "^1.0.1", + "google-gax": "^2.24.1", + "protobufjs": "^6.8.6" + }, + "engines": { + "node": ">=10.10.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==", + "dev": true, + "optional": true, + "dependencies": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.1.tgz", + "integrity": "sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.4.tgz", + "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/storage": { + "version": "5.19.4", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.19.4.tgz", + "integrity": "sha512-Jz7ugcPHhsEmMVvIxM9uoBsdEbKIYwDkh3u07tifsIymEWs47F4/D6+/Tv/W7kLhznqjyOjVJ/0frtBeIC0lJA==", + "dev": true, + "optional": true, + "dependencies": { + "@google-cloud/paginator": "^3.0.7", + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "abort-controller": "^3.0.0", + "arrify": "^2.0.0", + "async-retry": "^1.3.3", + "compressible": "^2.0.12", + "configstore": "^5.0.0", + "date-and-time": "^2.0.0", + "duplexify": "^4.0.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "get-stream": "^6.0.0", + "google-auth-library": "^7.14.1", + "hash-stream-validation": "^0.2.2", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "pumpify": "^2.0.0", + "retry-request": "^4.2.2", + "snakeize": "^0.1.0", + "stream-events": "^1.0.4", + "teeny-request": "^7.1.3", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/storage/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.6.7.tgz", + "integrity": "sha512-eBM03pu9hd3VqDQG+kHahiG1x80RGkkqqRb1Pchcwqej/KkAH95gAvKs6laqaHCycYaPK+TKuNQnOz9UXYA8qw==", + "dev": true, + "optional": true, + "dependencies": { + "@grpc/proto-loader": "^0.6.4", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@types/node": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", + "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==", + "dev": true, + "optional": true + }, + "node_modules/@grpc/proto-loader": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.9.tgz", + "integrity": "sha512-UlcCS8VbsU9d3XTXGiEVFonN7hXk+oMXZtoHHG2oSA1/GcDP1q6OUgs20PzHDGizzyi8ufGSUDlk3O2NyY7leg==", + "dev": true, + "optional": true, + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.10.0", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/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, + "optional": 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/@microsoft/api-documenter": { + "version": "7.17.11", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.17.11.tgz", + "integrity": "sha512-VdCu4eG5RISGEiG/hFO3jaN3gEgMZVXZRFpch/PQzrLO3Vh2QhZTz2LsZ2SYyb7UwBZCK9Z76ULv5cGoflylNA==", + "dev": true, + "dependencies": { + "@microsoft/api-extractor-model": "7.17.2", + "@microsoft/tsdoc": "0.14.1", + "@rushstack/node-core-library": "3.45.4", + "@rushstack/ts-command-line": "4.10.10", + "colors": "~1.2.1", + "js-yaml": "~3.13.1", + "resolve": "~1.17.0" + }, + "bin": { + "api-documenter": "bin/api-documenter" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/@microsoft/tsdoc": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", + "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "dev": true + }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/node-core-library": { + "version": "3.45.4", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.4.tgz", + "integrity": "sha512-FMoEQWjK7nWAO2uFgV1eVpVhY9ZDGOdIIomi9zTej64cKJ+8/Nvu+ny0xKaUDEjw/ALftN2D2ml7L0RDpW/Z9g==", + "dev": true, + "dependencies": { + "@types/node": "12.20.24", + "colors": "~1.2.1", + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.17.0", + "semver": "~7.3.0", + "timsort": "~0.3.0", + "z-schema": "~5.0.2" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/@rushstack/ts-command-line": { + "version": "4.10.10", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.10.tgz", + "integrity": "sha512-F+MH7InPDXqX40qvvcEsnvPpmg566SBpfFqj2fcCh8RjM6AyOoWlXc8zx7giBD3ZN85NVAEjZAgrcLU0z+R2yg==", + "dev": true, + "dependencies": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/@types/node": { + "version": "12.20.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", + "dev": true + }, + "node_modules/@microsoft/api-documenter/node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/@microsoft/api-documenter/node_modules/z-schema": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.3.tgz", + "integrity": "sha512-sGvEcBOTNum68x9jCpCVGPFJ6mWnkD0YxOcddDlJHRx3tKdB2q8pCHExMVZo/AV/6geuVJXG7hljDaWG8+5GDw==", + "dev": true, + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^2.20.3" + } + }, + "node_modules/@microsoft/api-extractor": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.23.0.tgz", + "integrity": "sha512-fbdX05RVE1EMA7nvyRHuS9nx1pryhjgURDx6pQlE/9yOXQ5PO7MpYdfWGaRsQwyYuU3+tPxgro819c0R3AK6KA==", + "dev": true, + "dependencies": { + "@microsoft/api-extractor-model": "7.17.2", + "@microsoft/tsdoc": "0.14.1", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "3.45.4", + "@rushstack/rig-package": "0.3.11", + "@rushstack/ts-command-line": "4.10.10", + "colors": "~1.2.1", + "lodash": "~4.17.15", + "resolve": "~1.17.0", + "semver": "~7.3.0", + "source-map": "~0.6.1", + "typescript": "~4.6.3" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.17.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.17.2.tgz", + "integrity": "sha512-fYfCeBeLm7jnZligC64qHiH4/vzswFLDfyPpX+uKO36OI2kIeMHrYG0zaezmuinKvE4vg1dAz38zZeDbPvBKGg==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.1", + "@microsoft/tsdoc-config": "~0.16.1", + "@rushstack/node-core-library": "3.45.4" + } + }, + "node_modules/@microsoft/api-extractor-model/node_modules/@microsoft/tsdoc": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", + "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "dev": true + }, + "node_modules/@microsoft/api-extractor-model/node_modules/@rushstack/node-core-library": { + "version": "3.45.4", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.4.tgz", + "integrity": "sha512-FMoEQWjK7nWAO2uFgV1eVpVhY9ZDGOdIIomi9zTej64cKJ+8/Nvu+ny0xKaUDEjw/ALftN2D2ml7L0RDpW/Z9g==", + "dev": true, + "dependencies": { + "@types/node": "12.20.24", + "colors": "~1.2.1", + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.17.0", + "semver": "~7.3.0", + "timsort": "~0.3.0", + "z-schema": "~5.0.2" + } + }, + "node_modules/@microsoft/api-extractor-model/node_modules/@types/node": { + "version": "12.20.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", + "dev": true + }, + "node_modules/@microsoft/api-extractor-model/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@microsoft/api-extractor-model/node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/@microsoft/api-extractor-model/node_modules/z-schema": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.3.tgz", + "integrity": "sha512-sGvEcBOTNum68x9jCpCVGPFJ6mWnkD0YxOcddDlJHRx3tKdB2q8pCHExMVZo/AV/6geuVJXG7hljDaWG8+5GDw==", + "dev": true, + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^2.20.3" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@microsoft/tsdoc": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", + "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "dev": true + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/node-core-library": { + "version": "3.45.4", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.4.tgz", + "integrity": "sha512-FMoEQWjK7nWAO2uFgV1eVpVhY9ZDGOdIIomi9zTej64cKJ+8/Nvu+ny0xKaUDEjw/ALftN2D2ml7L0RDpW/Z9g==", + "dev": true, + "dependencies": { + "@types/node": "12.20.24", + "colors": "~1.2.1", + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.17.0", + "semver": "~7.3.0", + "timsort": "~0.3.0", + "z-schema": "~5.0.2" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@rushstack/ts-command-line": { + "version": "4.10.10", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.10.tgz", + "integrity": "sha512-F+MH7InPDXqX40qvvcEsnvPpmg566SBpfFqj2fcCh8RjM6AyOoWlXc8zx7giBD3ZN85NVAEjZAgrcLU0z+R2yg==", + "dev": true, + "dependencies": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/@types/node": { + "version": "12.20.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", + "dev": true + }, + "node_modules/@microsoft/api-extractor/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/z-schema": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.3.tgz", + "integrity": "sha512-sGvEcBOTNum68x9jCpCVGPFJ6mWnkD0YxOcddDlJHRx3tKdB2q8pCHExMVZo/AV/6geuVJXG7hljDaWG8+5GDw==", + "dev": true, + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^2.20.3" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.12.24", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.12.24.tgz", + "integrity": "sha512-Mfmij13RUTmHEMi9vRUhMXD7rnGR2VvxeNYtaGtaJ4redwwjT4UXYJ+nzmVJF7hhd4pn/Fx5sncDKxMVFJSWPg==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz", + "integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.14.1", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/@microsoft/tsdoc": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz", + "integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==", + "dev": true + }, + "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", + "dev": true, + "optional": true + }, + "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==", + "dev": true, + "optional": true + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true, + "optional": true + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", + "dev": true, + "optional": true + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dev": true, + "optional": true, + "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": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", + "dev": true, + "optional": true + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", + "dev": true, + "optional": true + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", + "dev": true, + "optional": true + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", + "dev": true, + "optional": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "dev": true, + "optional": true + }, + "node_modules/@rushstack/node-core-library": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.36.0.tgz", + "integrity": "sha512-bID2vzXpg8zweXdXgQkKToEdZwVrVCN9vE9viTRk58gqzYaTlz4fMId6V3ZfpXN6H0d319uGi2KDlm+lUEeqCg==", + "dev": true, + "dependencies": { + "@types/node": "10.17.13", + "colors": "~1.2.1", + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.17.0", + "semver": "~7.3.0", + "timsort": "~0.3.0", + "z-schema": "~3.18.3" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/@types/node": { + "version": "10.17.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", + "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==", + "dev": true + }, + "node_modules/@rushstack/node-core-library/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.11.tgz", + "integrity": "sha512-uI1/g5oQPtyrT9nStoyX/xgZSLa2b+srRFaDk3r1eqC7zA5th4/bvTGl2QfV3C9NcP+coSqmk5mFJkUfH6i3Lw==", + "dev": true, + "dependencies": { + "resolve": "~1.17.0", + "strip-json-comments": "~3.1.1" + } + }, + "node_modules/@rushstack/rig-package/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@rushstack/rig-package/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/@rushstack/ts-command-line": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.7.8.tgz", + "integrity": "sha512-8ghIWhkph7NnLCMDJtthpsb7TMOsVGXVDvmxjE/CeklTqjbbUFBjGXizJfpbEkRQTELuZQ2+vGn7sGwIWKN2uA==", + "dev": true, + "dependencies": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "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==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true + }, + "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/body-parser/node_modules/@types/node": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", + "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" + }, + "node_modules/@types/chai": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz", + "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==", + "dev": true + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz", + "integrity": "sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ==", + "dev": true, + "dependencies": { + "@types/chai": "*" + } + }, + "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/connect/node_modules/@types/node": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", + "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" + }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "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-jwt": { + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.42.tgz", + "integrity": "sha512-WszgUddvM1t5dPpJ3LhWNH8kfNN8GPIBrAGxgIYXVCEGx6Bx4A036aAuf/r5WH9DIEdlmp7gHOYvSM6U87B0ag==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/express-unless": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/express-serve-static-core/node_modules/@types/node": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", + "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" + }, + "node_modules/@types/express-unless": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", + "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz", + "integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.14.182", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", + "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", + "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==", + "dev": true, + "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/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "node_modules/@types/mock-require": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mock-require/-/mock-require-2.0.1.tgz", + "integrity": "sha512-O7U5DVGboY/Crueb5/huUCIRjKtRVRaLmRDbZJBlDQgJn966z3aiFDN+6AtYviu2ExwMkl34LjT/IiC0OPtKuQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/nock": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@types/nock/-/nock-10.0.3.tgz", + "integrity": "sha512-OthuN+2FuzfZO3yONJ/QVjKmLEuRagS9TV9lEId+WHL9KhftYG+/2z+pxlr0UgVVXSpVD8woie/3fzQn8ft/Ow==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + }, + "node_modules/@types/node-fetch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-3.0.3.tgz", + "integrity": "sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==", + "deprecated": "This is a stub types definition. node-fetch provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "node-fetch": "*" + } + }, + "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/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static/node_modules/@types/node": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", + "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" + }, + "node_modules/@types/sinon": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.2.tgz", + "integrity": "sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": 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==", + "dev": true, + "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.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.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/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==", + "dev": 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==", + "dev": true + }, + "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/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "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/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "node_modules/api-extractor-model-me": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/api-extractor-model-me/-/api-extractor-model-me-0.1.1.tgz", + "integrity": "sha512-Ez801ZMADfkseOWNRFquvyQYDm3D9McpxfkKMWL6JFCGcpub0miJ+TFNphIR1nSZbrsxz3kIeOovNMY4VlL6Bw==", + "dev": true, + "dependencies": { + "@microsoft/tsdoc": "0.12.24", + "@rushstack/node-core-library": "3.36.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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, + "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": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "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==", + "dev": true, + "optional": true, + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "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/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" + } + ], + "optional": true + }, + "node_modules/bignumber.js": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", + "dev": true, + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "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.10.3", + "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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "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/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": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, + "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/chalk/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/chalk/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/chalk/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/chalk/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/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/child-process-promise": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/child-process-promise/-/child-process-promise-2.2.1.tgz", + "integrity": "sha1-RzChHvYQ+tRQuPIjx50x172tgHQ=", + "dev": true, + "dependencies": { + "cross-spawn": "^4.0.2", + "node-version": "^1.0.0", + "promise-polyfill": "^6.0.1" + } + }, + "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, + "optional": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "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/colors": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", + "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "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": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "optional": true, + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "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": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "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/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/date-and-time": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.3.1.tgz", + "integrity": "sha512-OaIRmSJXifwEN21rMVVDs0Kz8uhJ3wWPYd86atkRiqN54liaMQYEbbrgjZQea75YXOBWL4ZFb3rG/waenw1TEg==", + "dev": true, + "optional": true + }, + "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/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "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/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.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/dicer": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.1.tgz", + "integrity": "sha512-ObioMtXnmjYs3aRtpIJt9rgQSPCIhKVkFPip+E9GUDyWl8N435znUxK/JfNwGZJ2wnn5JKQ7Ly3vOK5Q5dylGA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "optional": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "dev": true, + "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==", + "dev": true, + "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": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.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==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "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==", + "dev": true, + "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": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true, + "optional": true + }, + "node_modules/es-abstract": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "optional": 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": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz", + "integrity": "sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.1", + "jest-docblock": "^21.0.0" + }, + "engines": { + "node": ">=4.0.0" + }, + "peerDependencies": { + "prettier": ">= 0.11.0" + } + }, + "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==", + "dev": 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==", + "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/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "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==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.0.tgz", + "integrity": "sha512-EJEXxiTQJS3lIPrU1AE2vRuT7X7E+0KBbpm5GSoK524yl0K8X+er8zS2P14E64eqsVNoWbMCT7MpmQ+ErAhgRg==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "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.10.3", + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": 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 + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/firebase-admin": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-10.1.0.tgz", + "integrity": "sha512-4i4wu+EFgNfY4+D4DxXkZcmbD832ozUMNvHMkOFQrf8upyp51n6jrDJS+wLok9sd62yeqcImbnsLOympGlISPA==", + "dev": true, + "dependencies": { + "@firebase/database-compat": "^0.1.1", + "@firebase/database-types": "^0.9.3", + "@types/node": ">=12.12.47", + "dicer": "^0.3.0", + "jsonwebtoken": "^8.5.1", + "jwks-rsa": "^2.0.2", + "node-forge": "^1.3.1" + }, + "engines": { + "node": ">=12.7.0" + }, + "optionalDependencies": { + "@google-cloud/firestore": "^4.15.1", + "@google-cloud/storage": "^5.18.3" + } + }, + "node_modules/firebase-admin/node_modules/@types/node": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", + "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==", + "dev": true + }, + "node_modules/flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "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": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "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": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true, + "optional": true + }, + "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/gaxios": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", + "integrity": "sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA==", + "dev": true, + "optional": true, + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "dev": true, + "optional": true, + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "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": "*" + } + }, + "node_modules/google-auth-library": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz", + "integrity": "sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA==", + "dev": true, + "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": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-auth-library/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, + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-auth-library/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, + "optional": true + }, + "node_modules/google-gax": { + "version": "2.30.2", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.30.2.tgz", + "integrity": "sha512-BCNCT26kb0iC52zj2SosyOZMhI5sVfXuul1h0Aw5uT9nGAbmS5eOvQ49ft53ft6XotDj11sUSDV6XESEiQqCqg==", + "dev": true, + "optional": true, + "dependencies": { + "@grpc/grpc-js": "~1.6.0", + "@grpc/proto-loader": "^0.6.1", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^4.0.0", + "fast-text-encoding": "^1.0.3", + "google-auth-library": "^7.14.0", + "is-stream-ended": "^0.1.4", + "node-fetch": "^2.6.1", + "object-hash": "^3.0.0", + "proto3-json-serializer": "^0.1.8", + "protobufjs": "6.11.2", + "retry-request": "^4.0.0" + }, + "bin": { + "compileProtos": "build/tools/compileProtos.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-p12-pem": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz", + "integrity": "sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg==", + "dev": true, + "optional": true, + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "dev": true, + "optional": true, + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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-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": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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-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/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/hash-stream-validation": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", + "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==", + "dev": true, + "optional": true + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "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/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "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.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": 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==", + "dev": 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==", + "dev": true + }, + "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/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==", + "dev": true, + "peer": true + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "optional": 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": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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==" + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "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-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-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-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "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" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-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-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-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-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-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-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-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "optional": 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==", + "dev": true, + "optional": true + }, + "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-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true, + "optional": true + }, + "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": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/jest-docblock": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz", + "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==", + "dev": true + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", + "dev": true + }, + "node_modules/jose": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", + "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", + "dev": true, + "dependencies": { + "@panva/asn1.js": "^1.0.0" + }, + "engines": { + "node": ">=10.13.0 < 13 || >=13.7.0" + }, + "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 + }, + "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, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/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/jsdom/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/jsdom/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/jsdom/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/jsdom/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "optional": true, + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "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-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dev": true, + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dev": true, + "optional": true, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "dev": true, + "dependencies": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwks-rsa": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.0.tgz", + "integrity": "sha512-GKOSDBWWBCiQTzawei6mEdRQvji5gecj8F9JwMt0ZOPnBPSmTjo5CKFvvbhE7jGPkU159Cpi0+OTLuABFcNOQQ==", + "dev": true, + "dependencies": { + "@types/express-jwt": "0.0.42", + "debug": "^4.3.4", + "jose": "^2.0.5", + "limiter": "^1.1.5", + "lru-memoizer": "^2.1.4" + }, + "engines": { + "node": ">=10 < 13 || >=14" + } + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true, + "optional": true, + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": 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==", + "dev": true + }, + "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/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true, + "optional": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", + "dev": true + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=", + "dev": true + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=", + "dev": true + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "dev": true, + "optional": true + }, + "node_modules/loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/lru-memoizer": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", + "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", + "dev": true, + "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": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "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, + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/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, + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/marked": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", + "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "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": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "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/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/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", + "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", + "dev": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.4", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mocha/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/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/mocha/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/mocha/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/mocha/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/mocha/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/mocha/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/mocha/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/mocha/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/mocha/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.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": "^13.1.2" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/mock-require": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", + "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", + "dev": true, + "dependencies": { + "get-caller-file": "^1.0.2", + "normalize-path": "^2.1.1" + }, + "engines": { + "node": ">=4.3.0" + } + }, + "node_modules/mock-require/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "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/nise": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", + "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", + "dev": true, + "dependencies": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^5.0.1", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/lolex": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", + "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/nise/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/nock": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/nock/-/nock-10.0.6.tgz", + "integrity": "sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w==", + "dev": true, + "dependencies": { + "chai": "^4.1.2", + "debug": "^4.1.0", + "deep-equal": "^1.0.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.5", + "mkdirp": "^0.5.0", + "propagate": "^1.0.0", + "qs": "^6.5.1", + "semver": "^5.5.0" + }, + "engines": { + "node": ">= 6.0" + } + }, + "node_modules/nock/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/nock/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/nock/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node_modules/node-environment-flags/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "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/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-version": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/node-version/-/node-version-1.2.0.tgz", + "integrity": "sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "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==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "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.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", + "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.8" + }, + "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": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": 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==", + "dev": true, + "optional": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/portfinder/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/portfinder/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/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "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/promise-polyfill": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz", + "integrity": "sha1-36lpQ+qcEh/KTem1hoyznTRy4Fc=", + "dev": true + }, + "node_modules/propagate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz", + "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=", + "dev": true, + "engines": [ + "node >= 0.8.1" + ] + }, + "node_modules/proto3-json-serializer": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-0.1.8.tgz", + "integrity": "sha512-ACilkB6s1U1gWnl5jtICpnDai4VCxmI9GFxuEaYdxtDG2oVI3sVFIUsvUZcQbJgtPM6p+zqKbjTKQZp6Y4FpQw==", + "dev": true, + "optional": true, + "dependencies": { + "protobufjs": "^6.11.2" + } + }, + "node_modules/protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "dev": true, + "hasInstallScript": true, + "optional": 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/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/protobufjs/node_modules/@types/node": { + "version": "17.0.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", + "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==", + "dev": true, + "optional": true + }, + "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": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "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, + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "dev": true, + "optional": true, + "dependencies": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "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/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/retry-request": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", + "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", + "dev": true, + "optional": true, + "dependencies": { + "debug": "^4.1.1", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "optional": true + }, + "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/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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/semver/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/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/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/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shiki": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "5.2.0" + } + }, + "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, + "optional": true + }, + "node_modules/sinon": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.3", + "diff": "^3.5.0", + "lolex": "^4.2.0", + "nise": "^1.5.2", + "supports-color": "^5.5.0" + } + }, + "node_modules/sinon/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/snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=", + "dev": true, + "optional": true + }, + "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/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "optional": true + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "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==", + "dev": true, + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "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.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "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": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", + "dev": true, + "optional": true + }, + "node_modules/supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/teeny-request": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.2.0.tgz", + "integrity": "sha512-SyY0pek1zWsi0LRVAALem+avzMLc33MKW/JLLakdP4s9+D7+jHcy5x6P+h94g2QNZsAqQNfX5lsbd3WSeJXrrw==", + "dev": true, + "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": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", + "dev": true + }, + "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/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "node_modules/ts-node": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", + "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.0", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" + } + }, + "node_modules/tslint-config-prettier": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", + "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", + "dev": true, + "bin": { + "tslint-config-prettier-check": "bin/check.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/tslint-no-unused-expression-chai": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/tslint-no-unused-expression-chai/-/tslint-no-unused-expression-chai-0.1.4.tgz", + "integrity": "sha512-frEWKNTcq7VsaWKgUxMDOB2N/cmQadVkUtUGIut+2K4nv/uFXPfgJyPjuNC/cHyfUVqIkHMAvHOCL+d/McU3nQ==", + "dev": true, + "dependencies": { + "tsutils": "^3.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "tslint": ">=5.1.0" + } + }, + "node_modules/tslint-no-unused-expression-chai/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/tslint-no-unused-expression-chai/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/tslint-plugin-prettier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-2.3.0.tgz", + "integrity": "sha512-F9e4K03yc9xuvv+A0v1EmjcnDwpz8SpCD8HzqSDe0eyg34cBinwn9JjmnnRrNAs4HdleRQj7qijp+P/JTxt4vA==", + "dev": true, + "dependencies": { + "eslint-plugin-prettier": "^2.2.0", + "lines-and-columns": "^1.1.6", + "tslib": "^1.7.1" + }, + "engines": { + "node": ">= 4" + }, + "peerDependencies": { + "prettier": "^1.9.0 || ^2.0.0", + "tslint": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/tslint-plugin-prettier/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/tslint/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslint/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tslint/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": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tsutils/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/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": 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, + "engines": { + "node": ">=4" + } + }, + "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/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "optional": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typedoc": { + "version": "0.22.17", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", + "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", + "dev": true, + "dependencies": { + "glob": "^8.0.3", + "lunr": "^2.3.9", + "marked": "^4.0.16", + "minimatch": "^5.1.0", + "shiki": "^0.10.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 12.10.0" + }, + "peerDependencies": { + "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x || 4.7.x" + } + }, + "node_modules/typedoc/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/typedoc/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "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/typedoc/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typescript": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "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/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "optional": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "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": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, + "optional": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "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==", + "dev": true, + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validator": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-8.2.0.tgz", + "integrity": "sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", + "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", + "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "dev": true + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/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-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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/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, + "optional": 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": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "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, + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.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": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs-unparser/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs-unparser/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/yargs-unparser/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/yargs-unparser/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/yargs-unparser/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/yargs-unparser/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/yargs-unparser/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs-unparser/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs-unparser/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs-unparser/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs-unparser/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/yargs-unparser/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.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": "^13.1.2" + } + }, + "node_modules/yargs-unparser/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/yargs/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/yargs/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/yargs/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/yargs/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/yargs/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/yargs/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/z-schema": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-3.18.4.tgz", + "integrity": "sha512-DUOKC/IhbkdLKKiV89gw9DUauTV8U/8yJl1sjf6MtDmzevLKOF2duNJ495S3MFVjqZarr+qNGCPbkg4mu4PpLw==", + "dev": true, + "dependencies": { + "lodash.get": "^4.0.0", + "lodash.isequal": "^4.0.0", + "validator": "^8.0.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "optionalDependencies": { + "commander": "^2.7.1" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.16.7", @@ -87,6 +6598,100 @@ } } }, + "@firebase/app": { + "version": "0.7.26", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.7.26.tgz", + "integrity": "sha512-FmJ4uaUyazmOZZWJO9OviKfnw+lrwMPQbWBMutymSQT8Gx783Ddnhs5IdmfV0NeLrlGy4ZwfP6/+RJyy2wGDXw==", + "dev": true, + "peer": true, + "requires": { + "@firebase/component": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.6.1", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "dependencies": { + "@firebase/component": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.15.tgz", + "integrity": "sha512-VRnZxmvtJmXupTPg37LxM0zdyMN54EXkmsFD4x5Bm4eZUay9VGnhfiGnE3m9Af/2hnURA2idIBN/23L6982iPQ==", + "dev": true, + "peer": true, + "requires": { + "@firebase/util": "1.6.1", + "tslib": "^2.1.0" + } + }, + "@firebase/logger": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.3.tgz", + "integrity": "sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q==", + "dev": true, + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "@firebase/util": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.1.tgz", + "integrity": "sha512-+eDE6uG5GgvXYHbAzfP1mpJUX1VDBD+A8CjBeBoNAKAVAApMSDxDODqRcOq7NW7kFJXSUkMzDJWhnUIifX2R8w==", + "dev": true, + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + } + } + }, + "@firebase/app-compat": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.27.tgz", + "integrity": "sha512-0A5ENP/KK0Eev94qPuxaclfOE0oA6hyCVQTdi0ox1bPm+VzGGD/jXP6Bzw+IUmy33ChjP/639bm6Myh8AG4PwA==", + "dev": true, + "peer": true, + "requires": { + "@firebase/app": "0.7.26", + "@firebase/component": "0.5.15", + "@firebase/logger": "0.3.3", + "@firebase/util": "1.6.1", + "tslib": "^2.1.0" + }, + "dependencies": { + "@firebase/component": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.5.15.tgz", + "integrity": "sha512-VRnZxmvtJmXupTPg37LxM0zdyMN54EXkmsFD4x5Bm4eZUay9VGnhfiGnE3m9Af/2hnURA2idIBN/23L6982iPQ==", + "dev": true, + "peer": true, + "requires": { + "@firebase/util": "1.6.1", + "tslib": "^2.1.0" + } + }, + "@firebase/logger": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.3.tgz", + "integrity": "sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q==", + "dev": true, + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "@firebase/util": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.6.1.tgz", + "integrity": "sha512-+eDE6uG5GgvXYHbAzfP1mpJUX1VDBD+A8CjBeBoNAKAVAApMSDxDODqRcOq7NW7kFJXSUkMzDJWhnUIifX2R8w==", + "dev": true, + "peer": true, + "requires": { + "tslib": "^2.1.0" + } + } + } + }, "@firebase/app-types": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.7.0.tgz", @@ -97,7 +6702,8 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz", "integrity": "sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==", - "dev": true + "dev": true, + "requires": {} }, "@firebase/component": { "version": "0.5.13", @@ -2290,19 +8896,6 @@ "jws": "^4.0.0" } }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2473,6 +9066,13 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==", + "dev": true, + "peer": true + }, "import-lazy": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", @@ -3180,9 +9780,9 @@ "dev": true }, "marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", + "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", "dev": true }, "media-typer": { @@ -3469,12 +10069,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, - "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 - }, "nise": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", @@ -3570,6 +10164,7 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, "requires": { "whatwg-url": "^5.0.0" } @@ -3813,12 +10408,6 @@ "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", "dev": true }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "promise-polyfill": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz", @@ -4130,9 +10719,9 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "shiki": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.15.tgz", - "integrity": "sha512-/Y0z9IzhJ8nD9nbceORCqu6NgT9X6I8Fk8c3SICHI5NbZRLdZYFaB233gwct9sU0vvSypyaL/qaKvzyQGJBZSw==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", + "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", "dev": true, "requires": { "jsonc-parser": "^3.0.0", @@ -4230,6 +10819,16 @@ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", "dev": 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==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, "string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -4267,16 +10866,6 @@ "define-properties": "^1.1.3" } }, - "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==", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4377,7 +10966,8 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true }, "ts-node": { "version": "10.7.0", @@ -4564,57 +11154,57 @@ } }, "typedoc": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.21.2.tgz", - "integrity": "sha512-SR1ByJB3USg+jxoxwzMRP07g/0f/cQUE5t7gOh1iTUyjTPyJohu9YSKRlK+MSXXqlhIq+m0jkEHEG5HoY7/Adg==", + "version": "0.22.17", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", + "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", "dev": true, "requires": { - "glob": "^7.1.7", - "handlebars": "^4.7.7", - "lodash": "^4.17.21", + "glob": "^8.0.3", "lunr": "^2.3.9", - "marked": "^2.1.1", - "minimatch": "^3.0.0", - "progress": "^2.0.3", - "shiki": "^0.9.3", - "typedoc-default-themes": "^0.12.10" + "marked": "^4.0.16", + "minimatch": "^5.1.0", + "shiki": "^0.10.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" + } + }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", "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" + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" } } } }, - "typedoc-default-themes": { - "version": "0.12.10", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz", - "integrity": "sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==", - "dev": true - }, "typescript": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true }, - "uglify-js": { - "version": "3.15.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", - "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", - "dev": true, - "optional": true - }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -4726,7 +11316,8 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true }, "websocket-driver": { "version": "0.7.4", @@ -4764,6 +11355,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -4845,12 +11437,6 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -4886,7 +11472,8 @@ "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true + "dev": true, + "requires": {} }, "xdg-basedir": { "version": "4.0.0", diff --git a/package.json b/package.json index 168e595ac..0001abce2 100644 --- a/package.json +++ b/package.json @@ -21,37 +21,25 @@ "files": [ "lib" ], - "main": "lib/index.js", + "main": "lib/v1/index.js", "bin": { "firebase-functions": "./lib/bin/firebase-functions.js" }, - "types": "lib/index.d.ts", + "types": "lib/v1/index.d.ts", "exports": { - ".": "./lib/index.js", + ".": "./lib/v1/index.js", "./logger/compat": "./lib/logger/compat.js", - "./lib/logger/compat": "./lib/logger/compat.js", "./logger": "./lib/logger/index.js", - "./lib/logger": "./lib/logger/index.js", - "./lib/providers/auth": "./lib/providers/auth.js", - "./lib/providers/analytics": "./lib/providers/analytics.js", - "./lib/providers/database": "./lib/providers/database.js", - "./lib/providers/firestore": "./lib/providers/firestore.js", - "./lib/providers/https": "./lib/providers/https.js", - "./lib/providers/pubsub": "./lib/providers/pubsub.js", - "./lib/providers/remoteConfig": "./lib/providers/remoteConfig.js", - "./lib/providers/storage": "./lib/providers/storage.js", - "./lib/providers/tasks": "./lib/providers/tasks.js", - "./lib/providers/testLab": "./lib/providers/testLab.js", - "./v1": "./lib/index.js", - "./v1/analytics": "./lib/providers/analytics.js", - "./v1/auth": "./lib/providers/auth.js", - "./v1/database": "./lib/providers/database.js", - "./v1/firestore": "./lib/providers/firestore.js", - "./v1/https": "./lib/providers/https.js", - "./v1/pubsub": "./lib/providers/pubsub.js", - "./v1/remoteConfig": "./lib/providers/remoteConfig.js", - "./v1/storage": "./lib/providers/storage.js", - "./v1/testLab": "./lib/providers/testLab.js", + "./v1": "./lib/v1/index.js", + "./v1/analytics": "./lib/v1/providers/analytics.js", + "./v1/auth": "./lib/v1/providers/auth.js", + "./v1/database": "./lib/v1/providers/database.js", + "./v1/firestore": "./lib/v1/providers/firestore.js", + "./v1/pubsub": "./lib/v1/providers/pubsub.js", + "./v1/remoteConfig": "./lib/v1/providers/remoteConfig.js", + "./v1/storage": "./lib/v1/providers/storage.js", + "./v1/tasks": "./lib/v1/providers/tasks.js", + "./v1/testLab": "./lib/v1/providers/testLab.js", "./v2": "./lib/v2/index.js", "./v2/core": "./lib/v2/core.js", "./v2/options": "./lib/v2/options.js", @@ -77,37 +65,34 @@ "lib/logger/compat" ], "v1": [ - "lib" + "lib/v1" ], "v1/analytics": [ - "lib/providers/analytics" + "./lib/v1/providers/analytics" ], "v1/auth": [ - "lib/providers/auth" + "./lib/v1/providers/auth" ], "v1/database": [ - "lib/providers/database" + "./lib/v1/privders/database" ], "v1/firestore": [ - "lib/providers/firestore" - ], - "v1/https": [ - "lib/providers/https" + "./lib/v1/providers/firestore" ], "v1/pubsub": [ - "lib/providers/pubsub" + "./lib/v1/providers/pubsub" ], - "v1/remoteConfig": [ - "lib/providers/remoteConfig" + "/v1/remoteConfig": [ + "./lib/v1/providers/remoteConfig" ], - "v1/storage": [ - "lib/providers/storage" + "/v1/storage": [ + "./lib/v1/providers/storage" ], - "v1/tasks": [ - "lib/providers/tasks" + "/v1/tasks": [ + "./lib/v1/providers/tasks" ], - "v1/testLab": [ - "lib/providers/testLab" + "/v1/testLab": [ + "./lib/v1/providers/testLab" ], "v2": [ "lib/v2" @@ -222,8 +207,8 @@ "tslint-config-prettier": "^1.18.0", "tslint-no-unused-expression-chai": "^0.1.4", "tslint-plugin-prettier": "^2.0.1", - "typedoc": "0.21.2", - "typescript": "^4.3.5", + "typedoc": "^0.22.17", + "typescript": "^4.6.3", "yargs": "^15.3.1" }, "peerDependencies": { diff --git a/spec/v1/setup.spec.ts b/spec/common/config.spec.ts similarity index 50% rename from spec/v1/setup.spec.ts rename to spec/common/config.spec.ts index 25a6fbe0c..17f33f033 100644 --- a/spec/v1/setup.spec.ts +++ b/spec/common/config.spec.ts @@ -21,30 +21,60 @@ // SOFTWARE. import { expect } from 'chai'; -import { setup } from '../../src/setup'; +import * as fs from 'fs'; +import * as process from 'process'; +import Sinon = require('sinon'); + +import { firebaseConfig, resetCache } from '../../src/common/config'; + +describe('firebaseConfig()', () => { + let readFileSync: Sinon.SinonStub; + let cwdStub: Sinon.SinonStub; + + before(() => { + readFileSync = Sinon.stub(fs, 'readFileSync'); + readFileSync.throws('Unexpected call'); + cwdStub = Sinon.stub(process, 'cwd'); + cwdStub.returns('/srv'); + }); + + after(() => { + Sinon.verifyAndRestore(); + }); -describe('setup()', () => { afterEach(() => { + resetCache(); + delete process.env.FIREBASE_CONFIG; - delete process.env.GCLOUD_PROJECT; + delete process.env.K_CONFIGURATION; }); - it('sets GCLOUD_PROJECT from FIREBASE_CONFIG', () => { - const testProject = 'test-project'; + it('loads Firebase configs from FIREBASE_CONFIG env variable', () => { process.env.FIREBASE_CONFIG = JSON.stringify({ - projectId: testProject, + databaseURL: 'foo@firebaseio.com', }); - setup(); - expect(process.env.GCLOUD_PROJECT).to.equal(testProject); + expect(firebaseConfig()).to.have.property( + 'databaseURL', + 'foo@firebaseio.com' + ); }); - it('does not set GCLOUD_PROJECT if already defined', () => { - const existingProject = 'test-project'; - process.env.GCLOUD_PROJECT = existingProject; - process.env.FIREBASE_CONFIG = JSON.stringify({ - projectId: 'new-project', - }); - setup(); - expect(process.env.GCLOUD_PROJECT).to.equal(existingProject); + it('loads Firebase configs from FIREBASE_CONFIG env variable pointing to a file', () => { + const oldEnv = process.env; + (process as any).env = { + ...oldEnv, + FIREBASE_CONFIG: '.firebaseconfig.json', + }; + try { + readFileSync.returns( + Buffer.from('{"databaseURL": "foo@firebaseio.com"}') + ); + expect(firebaseConfig()).to.have.property( + 'databaseURL', + 'foo@firebaseio.com' + ); + } finally { + (process as any).env = oldEnv; + } }); }); diff --git a/spec/utilities/path-pattern.spec.ts b/spec/common/utilities/path-pattern.spec.ts similarity index 98% rename from spec/utilities/path-pattern.spec.ts rename to spec/common/utilities/path-pattern.spec.ts index 8fe513284..fcb20afee 100644 --- a/spec/utilities/path-pattern.spec.ts +++ b/spec/common/utilities/path-pattern.spec.ts @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. import { expect } from 'chai'; -import * as pathPattern from '../../src/utilities/path-pattern'; +import * as pathPattern from '../../../src/common/utilities/path-pattern'; describe('path-pattern', () => { describe('trimParam', () => { diff --git a/spec/utilities/path.spec.ts b/spec/common/utilities/path.spec.ts similarity index 90% rename from spec/utilities/path.spec.ts rename to spec/common/utilities/path.spec.ts index c0a5dc318..9f3f6b67f 100644 --- a/spec/utilities/path.spec.ts +++ b/spec/common/utilities/path.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { normalizePath, pathParts } from '../../src/utilities/path'; +import { normalizePath, pathParts } from '../../../src/common/utilities/path'; describe('utilities', () => { describe('path', () => { diff --git a/spec/fixtures/sources/commonjs-grouped/g1.js b/spec/fixtures/sources/commonjs-grouped/g1.js index 7250c863d..4ddf39aa3 100644 --- a/spec/fixtures/sources/commonjs-grouped/g1.js +++ b/spec/fixtures/sources/commonjs-grouped/g1.js @@ -1,4 +1,4 @@ -const functions = require("../../../../src/index"); +const functions = require("../../../../src/v1"); exports.groupedhttp = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); diff --git a/spec/fixtures/sources/commonjs-grouped/index.js b/spec/fixtures/sources/commonjs-grouped/index.js index aafcf8145..385f8ea79 100644 --- a/spec/fixtures/sources/commonjs-grouped/index.js +++ b/spec/fixtures/sources/commonjs-grouped/index.js @@ -1,5 +1,5 @@ -const functions = require("../../../../src/index"); -const functionsv2 = require("../../../../src/v2/index"); +const functions = require("../../../../src/v1"); +const functionsv2 = require("../../../../src/v2"); exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); diff --git a/spec/fixtures/sources/commonjs-main/functions.js b/spec/fixtures/sources/commonjs-main/functions.js index 526599142..31b0ae2fa 100644 --- a/spec/fixtures/sources/commonjs-main/functions.js +++ b/spec/fixtures/sources/commonjs-main/functions.js @@ -1,5 +1,5 @@ -const functions = require("../../../../src/index"); -const functionsv2 = require("../../../../src/v2/index"); +const functions = require("../../../../src/v1"); +const functionsv2 = require("../../../../src/v2"); exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); diff --git a/spec/fixtures/sources/commonjs/index.js b/spec/fixtures/sources/commonjs/index.js index 526599142..31b0ae2fa 100644 --- a/spec/fixtures/sources/commonjs/index.js +++ b/spec/fixtures/sources/commonjs/index.js @@ -1,5 +1,5 @@ -const functions = require("../../../../src/index"); -const functionsv2 = require("../../../../src/v2/index"); +const functions = require("../../../../src/v1"); +const functionsv2 = require("../../../../src/v2"); exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); diff --git a/spec/runtime/loader.spec.ts b/spec/runtime/loader.spec.ts index 9994557c4..5745fbda7 100644 --- a/spec/runtime/loader.spec.ts +++ b/spec/runtime/loader.spec.ts @@ -1,13 +1,13 @@ import { expect } from 'chai'; import * as path from 'path'; -import * as functions from '../../src/index'; import * as loader from '../../src/runtime/loader'; import { ManifestEndpoint, ManifestRequiredAPI, ManifestStack, } from '../../src/runtime/manifest'; +import * as functions from '../../src/v1'; describe('extractStack', () => { const httpFn = functions.https.onRequest(() => {}); diff --git a/spec/v1/cloud-functions.spec.ts b/spec/v1/cloud-functions.spec.ts index ab4209025..8eeeee3df 100644 --- a/spec/v1/cloud-functions.spec.ts +++ b/spec/v1/cloud-functions.spec.ts @@ -28,7 +28,7 @@ import { EventContext, makeCloudFunction, MakeCloudFunctionArgs, -} from '../../src'; +} from '../../src/v1'; describe('makeCloudFunction', () => { const cloudFunctionArgs: MakeCloudFunctionArgs = { @@ -40,7 +40,7 @@ describe('makeCloudFunction', () => { legacyEventType: 'providers/provider/eventTypes/event', }; - it('should put a __trigger/__endpoint on the returned CloudFunction', () => { + it('should put a __endpoint on the returned CloudFunction', () => { const cf = makeCloudFunction({ provider: 'mock.provider', eventType: 'mock.event', @@ -49,14 +49,6 @@ describe('makeCloudFunction', () => { handler: () => null, }); - expect(cf.__trigger).to.deep.equal({ - eventTrigger: { - eventType: 'mock.provider.mock.event', - resource: 'resource', - service: 'service', - }, - }); - expect(cf.__endpoint).to.deep.equal({ platform: 'gcfv1', eventTrigger: { @@ -70,17 +62,9 @@ describe('makeCloudFunction', () => { }); }); - it('should have legacy event type in __trigger/__endpoint if provided', () => { + it('should have legacy event type in __endpoint if provided', () => { const cf = makeCloudFunction(cloudFunctionArgs); - expect(cf.__trigger).to.deep.equal({ - eventTrigger: { - eventType: 'providers/provider/eventTypes/event', - resource: 'resource', - service: 'service', - }, - }); - expect(cf.__endpoint).to.deep.equal({ platform: 'gcfv1', eventTrigger: { diff --git a/spec/v1/config.spec.ts b/spec/v1/config.spec.ts index 8341d6a34..0555abc93 100644 --- a/spec/v1/config.spec.ts +++ b/spec/v1/config.spec.ts @@ -25,7 +25,7 @@ import * as fs from 'fs'; import * as process from 'process'; import Sinon = require('sinon'); -import * as config from '../../src/config'; +import { config, resetCache } from '../../src/v1/config'; describe('config()', () => { let readFileSync: Sinon.SinonStub; @@ -43,8 +43,7 @@ describe('config()', () => { }); afterEach(() => { - delete config.config.singleton; - (config as any).firebaseConfigCache = null; + resetCache(); delete process.env.FIREBASE_CONFIG; delete process.env.CLOUD_RUNTIME_CONFIG; delete process.env.K_CONFIGURATION; @@ -60,10 +59,7 @@ describe('config()', () => { .returns(Buffer.from(json)); process.env.K_CONFIGURATION = 'my-service'; - expect(() => config.config()).to.throw( - Error, - /transition to using environment variables/ - ); + expect(config).to.throw(Error, /transition to using environment variables/); }); it('loads config values from .runtimeconfig.json', () => { @@ -74,66 +70,8 @@ describe('config()', () => { readFileSync .withArgs('/srv/.runtimeconfig.json') .returns(Buffer.from(json)); - const loaded = config.config(); + const loaded = config(); expect(loaded).to.not.have.property('firebase'); expect(loaded).to.have.property('foo', 'bar'); }); - - it('does not provide firebase config if .runtimeconfig.json not invalid', () => { - readFileSync.withArgs('/srv/.runtimeconfig.json').returns('invalid JSON'); - expect(config.firebaseConfig()).to.be.null; - }); - - it('does not provide firebase config if .ruuntimeconfig.json has no firebase property', () => { - readFileSync - .withArgs('/srv/.runtimeconfig.json') - .returns(Buffer.from('{}')); - expect(config.firebaseConfig()).to.be.null; - }); - - it('loads Firebase configs from FIREBASE_CONFIG env variable', () => { - process.env.FIREBASE_CONFIG = JSON.stringify({ - databaseURL: 'foo@firebaseio.com', - }); - expect(config.firebaseConfig()).to.have.property( - 'databaseURL', - 'foo@firebaseio.com' - ); - }); - - it('loads Firebase configs from FIREBASE_CONFIG env variable pointing to a file', () => { - const oldEnv = process.env; - (process as any).env = { - ...oldEnv, - FIREBASE_CONFIG: '.firebaseconfig.json', - }; - try { - readFileSync.returns( - Buffer.from('{"databaseURL": "foo@firebaseio.com"}') - ); - expect(config.firebaseConfig()).to.have.property( - 'databaseURL', - 'foo@firebaseio.com' - ); - } finally { - (process as any).env = oldEnv; - } - }); - - it('accepts alternative locations for config file', () => { - process.env.CLOUD_RUNTIME_CONFIG = 'another.json'; - const json = JSON.stringify({ foo: 'bar', firebase: {} }); - readFileSync.withArgs('another.json').returns(Buffer.from(json)); - expect(config.firebaseConfig()).to.not.be.null; - expect(config.config()).to.have.property('foo', 'bar'); - }); - - it('accepts full JSON in env.CLOUD_RUNTIME_CONFIG', () => { - process.env.CLOUD_RUNTIME_CONFIG = JSON.stringify({ - foo: 'bar', - firebase: {}, - }); - expect(config.firebaseConfig()).to.not.be.null; - expect(config.config()).to.have.property('foo', 'bar'); - }); }); diff --git a/spec/v1/function-builder.spec.ts b/spec/v1/function-builder.spec.ts index 8e01cd87a..caf0332e0 100644 --- a/spec/v1/function-builder.spec.ts +++ b/spec/v1/function-builder.spec.ts @@ -22,7 +22,7 @@ import { expect } from 'chai'; -import * as functions from '../../src'; +import * as functions from '../../src/v1'; describe('FunctionBuilder', () => { before(() => { @@ -39,7 +39,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); + expect(fn.__endpoint.region).to.deep.equal(['us-east1']); }); it('should allow multiple supported regions to be set', () => { @@ -48,7 +48,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.regions).to.deep.equal(['us-east1', 'us-central1']); + expect(fn.__endpoint.region).to.deep.equal(['us-east1', 'us-central1']); }); it('should allow all supported regions to be set', () => { @@ -66,7 +66,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.regions).to.deep.equal([ + expect(fn.__endpoint.region).to.deep.equal([ 'us-central1', 'us-east1', 'us-east4', @@ -88,9 +88,9 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__trigger.failurePolicy).to.deep.equal({ retry: {} }); + expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); + expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); + expect(fn.__endpoint.eventTrigger.retry).to.deep.equal(true); }); it("should apply a default failure policy if it's aliased with `true`", () => { @@ -103,7 +103,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.failurePolicy).to.deep.equal({ retry: {} }); + expect(fn.__endpoint.eventTrigger.retry).to.deep.equal(true); }); it('should allow both supported region and valid runtime options to be set', () => { @@ -116,9 +116,9 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.regions).to.deep.equal(['europe-west2']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); + expect(fn.__endpoint.region).to.deep.equal(['europe-west2']); + expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); + expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); }); it('should allow both valid runtime options and supported region to be set in reverse order', () => { @@ -131,9 +131,9 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.regions).to.deep.equal(['europe-west1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); + expect(fn.__endpoint.region).to.deep.equal(['europe-west1']); + expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); + expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); }); it('should fail if supported region but invalid runtime options are set (reverse order)', () => { @@ -205,7 +205,7 @@ describe('FunctionBuilder', () => { .runWith({ ingressSettings: 'ALLOW_INTERNAL_ONLY' }) .https.onRequest(() => {}); - expect(fn.__trigger.ingressSettings).to.equal('ALLOW_INTERNAL_ONLY'); + expect(fn.__endpoint.ingressSettings).to.equal('ALLOW_INTERNAL_ONLY'); }); it('should throw an error if user chooses an invalid ingressSettings', () => { @@ -229,7 +229,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.vpcConnector).to.equal('test-connector'); + expect(fn.__endpoint.vpc.connector).to.equal('test-connector'); }); it('should allow a vpcConnectorEgressSettings to be set', () => { @@ -241,9 +241,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.vpcConnectorEgressSettings).to.equal( - 'PRIVATE_RANGES_ONLY' - ); + expect(fn.__endpoint.vpc.egressSettings).to.equal('PRIVATE_RANGES_ONLY'); }); it('should throw an error if user chooses an invalid vpcConnectorEgressSettings', () => { @@ -269,12 +267,11 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.serviceAccountEmail).to.equal(serviceAccount); + expect(fn.__endpoint.serviceAccountEmail).to.equal(serviceAccount); }); it('should allow a serviceAccount to be set with generated service account email', () => { const serviceAccount = 'test-service-account@'; - const projectId = process.env.GCLOUD_PROJECT; const fn = functions .runWith({ serviceAccount, @@ -282,9 +279,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.serviceAccountEmail).to.equal( - `test-service-account@${projectId}.iam.gserviceaccount.com` - ); + expect(fn.__endpoint.serviceAccountEmail).to.equal(`test-service-account@`); }); it('should set a null serviceAccountEmail if service account is set to `default`', () => { @@ -296,7 +291,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.serviceAccountEmail).to.be.null; + expect(fn.__endpoint.serviceAccountEmail).to.equal('default'); }); it('should throw an error if serviceAccount is set to an invalid value', () => { @@ -317,7 +312,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(4096); + expect(fn.__endpoint.availableMemoryMb).to.deep.equal(4096); }); it('should allow labels to be set', () => { @@ -330,7 +325,7 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.labels).to.deep.equal({ + expect(fn.__endpoint.labels).to.deep.equal({ 'valid-key': 'valid-value', }); }); @@ -487,7 +482,11 @@ describe('FunctionBuilder', () => { .auth.user() .onCreate((user) => user); - expect(fn.__trigger.secrets).to.deep.equal(secrets); + expect(fn.__endpoint.secretEnvironmentVariables).to.deep.equal([ + { + key: 'API_KEY', + }, + ]); }); it('should throw error given secrets expressed with full resource name', () => { diff --git a/spec/v1/providers/analytics.spec.input.ts b/spec/v1/providers/analytics.spec.input.ts index b4a6505f5..74ad65a93 100644 --- a/spec/v1/providers/analytics.spec.input.ts +++ b/spec/v1/providers/analytics.spec.input.ts @@ -21,7 +21,7 @@ // SOFTWARE. /* tslint:disable:max-line-length */ -import { AnalyticsEvent } from '../../../src/providers/analytics'; +import { AnalyticsEvent } from '../../../src/v1/providers/analytics'; // A payload, as it might arrive over the wire. Every possible field is filled out at least once. export const fullPayload = JSON.parse(`{ diff --git a/spec/v1/providers/analytics.spec.ts b/spec/v1/providers/analytics.spec.ts index ead39554f..f1fa2162f 100644 --- a/spec/v1/providers/analytics.spec.ts +++ b/spec/v1/providers/analytics.spec.ts @@ -22,9 +22,9 @@ import { expect } from 'chai'; -import * as functions from '../../../src'; -import { Event, EventContext } from '../../../src/cloud-functions'; -import * as analytics from '../../../src/providers/analytics'; +import * as functions from '../../../src/v1'; +import { Event, EventContext } from '../../../src/v1/cloud-functions'; +import * as analytics from '../../../src/v1/providers/analytics'; import * as analytics_spec_input from './analytics.spec.input'; describe('Analytics Functions', () => { @@ -47,10 +47,6 @@ describe('Analytics Functions', () => { .analytics.event('event') .onLog((event) => event); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); @@ -60,15 +56,6 @@ describe('Analytics Functions', () => { it('should return a trigger/endpoint with appropriate values', () => { const cloudFunction = analytics.event('first_open').onLog(() => null); - expect(cloudFunction.__trigger).to.deep.equal({ - eventTrigger: { - eventType: - 'providers/google.firebase.analytics/eventTypes/event.log', - resource: 'projects/project1/events/first_open', - service: 'app-measurement.com', - }, - }); - expect(cloudFunction.__endpoint).to.deep.equal({ platform: 'gcfv1', eventTrigger: { @@ -322,11 +309,10 @@ describe('Analytics Functions', () => { describe('handler namespace', () => { describe('#onLog', () => { - it('should return an empty trigger/endpoint', () => { + it('should return an empty endpoint', () => { const cloudFunction = functions.handler.analytics.event.onLog( () => null ); - expect(cloudFunction.__trigger).to.deep.equal({}); expect(cloudFunction.__endpoint).to.be.undefined; }); @@ -369,15 +355,15 @@ describe('Analytics Functions', () => { }); describe('process.env.GCLOUD_PROJECT not set', () => { - it('should not throw if __trigger is not accessed', () => { + it('should not throw if __endpoint is not accessed', () => { expect(() => analytics.event('event').onLog(() => null)).to.not.throw( Error ); }); - it('should throw when trigger is accessed', () => { + it('should throw when __endpoint is accessed', () => { expect( - () => analytics.event('event').onLog(() => null).__trigger + () => analytics.event('event').onLog(() => null).__endpoint ).to.throw(Error); }); diff --git a/spec/v1/providers/auth.spec.ts b/spec/v1/providers/auth.spec.ts index 91e394bc7..d440866e4 100644 --- a/spec/v1/providers/auth.spec.ts +++ b/spec/v1/providers/auth.spec.ts @@ -21,14 +21,14 @@ // SOFTWARE. import { expect } from 'chai'; +import { UserRecord } from '../../../src/common/providers/identity'; +import * as functions from '../../../src/v1'; import { CloudFunction, Event, EventContext, -} from '../../../src/cloud-functions'; -import { UserRecord } from '../../../src/common/providers/identity'; -import * as functions from '../../../src/index'; -import * as auth from '../../../src/providers/auth'; +} from '../../../src/v1/cloud-functions'; +import * as auth from '../../../src/v1/providers/auth'; describe('Auth Functions', () => { const event: Event = { @@ -50,16 +50,6 @@ describe('Auth Functions', () => { }; describe('AuthBuilder', () => { - function expectedTrigger(project: string, eventType: string) { - return { - eventTrigger: { - resource: `projects/${project}`, - eventType: `providers/firebase.auth/eventTypes/${eventType}`, - service: 'firebaseauth.googleapis.com', - }, - }; - } - function expectedEndpoint(project: string, eventType: string) { return { platform: 'gcfv1', @@ -98,9 +88,9 @@ describe('Auth Functions', () => { .auth.user() .onCreate(() => null); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); + expect(fn.__endpoint.region).to.deep.equal(['us-east1']); + expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); + expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); @@ -111,10 +101,6 @@ describe('Auth Functions', () => { it('should return a trigger/endpoint with appropriate values', () => { const cloudFunction = auth.user().onCreate(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(project, 'user.create') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(project, 'user.create') ); @@ -125,10 +111,6 @@ describe('Auth Functions', () => { it('should return a trigger/endpoint with appropriate values', () => { const cloudFunction = auth.user().onDelete(handler); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(project, 'user.delete') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(project, 'user.delete') ); @@ -139,17 +121,6 @@ describe('Auth Functions', () => { it('should create the function without options', () => { const fn = auth.user().beforeCreate((u, c) => Promise.resolve()); - expect(fn.__trigger).to.deep.equal({ - labels: {}, - blockingTrigger: { - eventType: 'providers/cloud.auth/eventTypes/user.beforeCreate', - options: { - accessToken: false, - idToken: false, - refreshToken: false, - }, - }, - }); expect(fn.__endpoint).to.deep.equal({ platform: 'gcfv1', labels: {}, @@ -185,20 +156,6 @@ describe('Auth Functions', () => { }) .beforeCreate((u, c) => Promise.resolve()); - expect(fn.__trigger).to.deep.equal({ - labels: {}, - regions: ['us-east1'], - availableMemoryMb: 256, - timeout: '90s', - blockingTrigger: { - eventType: 'providers/cloud.auth/eventTypes/user.beforeCreate', - options: { - accessToken: true, - idToken: false, - refreshToken: false, - }, - }, - }); expect(fn.__endpoint).to.deep.equal({ platform: 'gcfv1', labels: {}, @@ -227,17 +184,6 @@ describe('Auth Functions', () => { it('should create the function without options', () => { const fn = auth.user().beforeSignIn((u, c) => Promise.resolve()); - expect(fn.__trigger).to.deep.equal({ - labels: {}, - blockingTrigger: { - eventType: 'providers/cloud.auth/eventTypes/user.beforeSignIn', - options: { - accessToken: false, - idToken: false, - refreshToken: false, - }, - }, - }); expect(fn.__endpoint).to.deep.equal({ platform: 'gcfv1', labels: {}, @@ -273,20 +219,6 @@ describe('Auth Functions', () => { }) .beforeSignIn((u, c) => Promise.resolve()); - expect(fn.__trigger).to.deep.equal({ - labels: {}, - regions: ['us-east1'], - availableMemoryMb: 256, - timeout: '90s', - blockingTrigger: { - eventType: 'providers/cloud.auth/eventTypes/user.beforeSignIn', - options: { - accessToken: true, - idToken: false, - refreshToken: false, - }, - }, - }); expect(fn.__endpoint).to.deep.equal({ platform: 'gcfv1', labels: {}, @@ -337,11 +269,6 @@ describe('Auth Functions', () => { describe('handler namespace', () => { describe('#onCreate', () => { - it('should return an empty trigger', () => { - const cloudFunction = functions.handler.auth.user.onCreate(() => null); - expect(cloudFunction.__trigger).to.deep.equal({}); - }); - it('should return an empty endpoint', () => { const cloudFunction = functions.handler.auth.user.onCreate(() => null); expect(cloudFunction.__endpoint).to.be.undefined; @@ -353,11 +280,6 @@ describe('Auth Functions', () => { (data: UserRecord) => data ); - it('should return an empty trigger', () => { - const cloudFunction = functions.handler.auth.user.onDelete(() => null); - expect(cloudFunction.__trigger).to.deep.equal({}); - }); - it('should return an empty endpoint', () => { const cloudFunction = functions.handler.auth.user.onDelete(() => null); expect(cloudFunction.__endpoint).to.be.undefined; @@ -379,14 +301,10 @@ describe('Auth Functions', () => { }); describe('process.env.GCLOUD_PROJECT not set', () => { - it('should not throw if __trigger is not accessed', () => { + it('should not throw if __endpoint is not accessed', () => { expect(() => auth.user().onCreate(() => null)).to.not.throw(Error); }); - it('should throw when trigger is accessed', () => { - expect(() => auth.user().onCreate(() => null).__trigger).to.throw(Error); - }); - it('should throw when endpoint is accessed', () => { expect(() => auth.user().onCreate(() => null).__endpoint).to.throw(Error); }); diff --git a/spec/v1/providers/database.spec.ts b/spec/v1/providers/database.spec.ts index f044e2ca2..2ba48ef03 100644 --- a/spec/v1/providers/database.spec.ts +++ b/spec/v1/providers/database.spec.ts @@ -22,25 +22,15 @@ import { expect } from 'chai'; import { getApp, setApp } from '../../../src/common/app'; -import * as config from '../../../src/config'; -import * as functions from '../../../src/index'; -import * as database from '../../../src/providers/database'; -import { applyChange } from '../../../src/utils'; +import * as config from '../../../src/common/config'; +import { applyChange } from '../../../src/common/utilities/utils'; +import * as functions from '../../../src/v1'; +import * as database from '../../../src/v1/providers/database'; describe('Database Functions', () => { describe('DatabaseBuilder', () => { // TODO add tests for building a data or change based on the type of operation - function expectedTrigger(resource: string, eventType: string) { - return { - eventTrigger: { - resource, - eventType: `providers/google.firebase.database/eventTypes/${eventType}`, - service: 'firebaseio.com', - }, - }; - } - function expectedEndpoint(resource: string, eventType: string) { return { platform: 'gcfv1', @@ -56,13 +46,13 @@ describe('Database Functions', () => { } before(() => { - (config as any).firebaseConfigCache = { + config.resetCache({ databaseURL: 'https://subdomain.apse.firebasedatabase.app', - }; + }); }); after(() => { - (config as any).firebaseConfigCache = null; + config.resetCache(undefined); setApp(undefined); }); @@ -76,9 +66,9 @@ describe('Database Functions', () => { .database.ref('/') .onCreate((snap) => snap); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); + expect(fn.__endpoint.region).to.deep.equal(['us-east1']); + expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); + expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); @@ -86,16 +76,9 @@ describe('Database Functions', () => { }); describe('#onWrite()', () => { - it('should return a trigger/endpoint with appropriate values', () => { + it('should return a endpoint with appropriate values', () => { const func = database.ref('foo').onWrite(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger( - 'projects/_/instances/subdomain/refs/foo', - 'ref.write' - ) - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint( 'projects/_/instances/subdomain/refs/foo', @@ -110,10 +93,6 @@ describe('Database Functions', () => { .ref('foo') .onWrite(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger('projects/_/instances/custom/refs/foo', 'ref.write') - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint('projects/_/instances/custom/refs/foo', 'ref.write') ); @@ -147,13 +126,6 @@ describe('Database Functions', () => { it('should return a trigger/endpoint with appropriate values', () => { const func = database.ref('foo').onCreate(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger( - 'projects/_/instances/subdomain/refs/foo', - 'ref.create' - ) - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint( 'projects/_/instances/subdomain/refs/foo', @@ -168,10 +140,6 @@ describe('Database Functions', () => { .ref('foo') .onCreate(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger('projects/_/instances/custom/refs/foo', 'ref.create') - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint('projects/_/instances/custom/refs/foo', 'ref.create') ); @@ -206,13 +174,6 @@ describe('Database Functions', () => { it('should return a trigger/endpoint with appropriate values', () => { const func = database.ref('foo').onUpdate(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger( - 'projects/_/instances/subdomain/refs/foo', - 'ref.update' - ) - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint( 'projects/_/instances/subdomain/refs/foo', @@ -227,10 +188,6 @@ describe('Database Functions', () => { .ref('foo') .onUpdate(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger('projects/_/instances/custom/refs/foo', 'ref.update') - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint('projects/_/instances/custom/refs/foo', 'ref.update') ); @@ -265,13 +222,6 @@ describe('Database Functions', () => { it('should return a trigger/endpoint with appropriate values', () => { const func = database.ref('foo').onDelete(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger( - 'projects/_/instances/subdomain/refs/foo', - 'ref.delete' - ) - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint( 'projects/_/instances/subdomain/refs/foo', @@ -286,10 +236,6 @@ describe('Database Functions', () => { .ref('foo') .onDelete(() => null); - expect(func.__trigger).to.deep.equal( - expectedTrigger('projects/_/instances/custom/refs/foo', 'ref.delete') - ); - expect(func.__endpoint).to.deep.equal( expectedEndpoint('projects/_/instances/custom/refs/foo', 'ref.delete') ); @@ -323,9 +269,8 @@ describe('Database Functions', () => { describe('handler namespace', () => { describe('#onWrite()', () => { - it('correctly sets trigger to {}', () => { + it('correctly sets __endpoint to undefind', () => { const cf = functions.handler.database.ref.onWrite(() => null); - expect(cf.__trigger).to.deep.equal({}); expect(cf.__endpoint).to.be.undefined; }); @@ -333,7 +278,6 @@ describe('Database Functions', () => { const func = functions.handler.database.instance.ref.onWrite( () => null ); - expect(func.__trigger).to.deep.equal({}); expect(func.__endpoint).to.be.undefined; }); @@ -363,9 +307,8 @@ describe('Database Functions', () => { }); describe('#onCreate()', () => { - it('correctly sets trigger to {}', () => { + it('correctly sets endpoint to undefined', () => { const cf = functions.handler.database.ref.onCreate(() => null); - expect(cf.__trigger).to.deep.equal({}); expect(cf.__endpoint).to.be.undefined; }); @@ -373,7 +316,6 @@ describe('Database Functions', () => { const func = functions.handler.database.instance.ref.onCreate( () => null ); - expect(func.__trigger).to.deep.equal({}); expect(func.__endpoint).to.be.undefined; }); @@ -402,9 +344,8 @@ describe('Database Functions', () => { }); describe('#onUpdate()', () => { - it('correctly sets trigger to {}', () => { + it('correctly sets endpoint to undefined', () => { const cf = functions.handler.database.ref.onUpdate(() => null); - expect(cf.__trigger).to.deep.equal({}); expect(cf.__endpoint).to.be.undefined; }); @@ -412,7 +353,6 @@ describe('Database Functions', () => { const func = functions.handler.database.instance.ref.onUpdate( () => null ); - expect(func.__trigger).to.deep.equal({}); expect(func.__endpoint).to.be.undefined; }); @@ -441,9 +381,8 @@ describe('Database Functions', () => { }); describe('#onDelete()', () => { - it('correctly sets trigger to {}', () => { + it('correctly sets endpoint to undefined', () => { const cf = functions.handler.database.ref.onDelete(() => null); - expect(cf.__trigger).to.deep.equal({}); expect(cf.__endpoint).to.be.undefined; }); @@ -451,7 +390,6 @@ describe('Database Functions', () => { const func = functions.handler.database.instance.ref.onDelete( () => null ); - expect(func.__trigger).to.deep.equal({}); expect(func.__endpoint).to.be.undefined; }); @@ -482,18 +420,12 @@ describe('Database Functions', () => { }); describe('process.env.FIREBASE_CONFIG not set', () => { - it('should not throw if __trigger is not accessed', () => { + it('should not throw if __endpoint is not accessed', () => { expect(() => database.ref('/path').onWrite(() => null)).to.not.throw( Error ); }); - it('should throw when trigger is accessed', () => { - expect( - () => database.ref('/path').onWrite(() => null).__trigger - ).to.throw(Error); - }); - it('should throw when endpoint is accessed', () => { expect( () => database.ref('/path').onWrite(() => null).__endpoint diff --git a/spec/v1/providers/firestore.spec.ts b/spec/v1/providers/firestore.spec.ts index 49fae4fef..2bc094591 100644 --- a/spec/v1/providers/firestore.spec.ts +++ b/spec/v1/providers/firestore.spec.ts @@ -23,8 +23,8 @@ import { expect } from 'chai'; import { Timestamp } from 'firebase-admin/firestore'; -import * as functions from '../../../src/index'; -import * as firestore from '../../../src/providers/firestore'; +import * as functions from '../../../src/v1'; +import * as firestore from '../../../src/v1/providers/firestore'; describe('Firestore Functions', () => { function constructValue(fields: any) { @@ -90,16 +90,6 @@ describe('Firestore Functions', () => { } describe('document builders and event types', () => { - function expectedTrigger(resource: string, eventType: string) { - return { - eventTrigger: { - resource, - eventType: `providers/cloud.firestore/eventTypes/${eventType}`, - service: 'firestore.googleapis.com', - }, - }; - } - function expectedEndpoint(resource: string, eventType: string) { return { platform: 'gcfv1', @@ -129,10 +119,6 @@ describe('Firestore Functions', () => { .document('users/{uid}') .onWrite(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(resource, 'document.write') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(resource, 'document.write') ); @@ -146,10 +132,6 @@ describe('Firestore Functions', () => { .document('users/{uid}') .onWrite(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(resource, 'document.write') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(resource, 'document.write') ); @@ -162,10 +144,6 @@ describe('Firestore Functions', () => { .document('users/{uid}') .onWrite(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(resource, 'document.write') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(resource, 'document.write') ); @@ -180,10 +158,6 @@ describe('Firestore Functions', () => { .document('users/{uid}') .onWrite(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(resource, 'document.write') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(resource, 'document.write') ); @@ -199,10 +173,6 @@ describe('Firestore Functions', () => { .firestore.document('doc') .onCreate((snap) => snap); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); @@ -210,18 +180,12 @@ describe('Firestore Functions', () => { }); describe('process.env.GCLOUD_PROJECT not set', () => { - it('should not throw if __trigger is not accessed', () => { + it('should not throw if __endpoint is not accessed', () => { expect(() => firestore.document('input').onCreate(() => null) ).to.not.throw(Error); }); - it('should throw when trigger is accessed', () => { - expect( - () => firestore.document('input').onCreate(() => null).__trigger - ).to.throw(Error); - }); - it('should throw when endpoint is accessed', () => { expect( () => firestore.document('input').onCreate(() => null).__endpoint @@ -319,7 +283,7 @@ describe('Firestore Functions', () => { delete process.env.GCLOUD_PROJECT; }); - it('constructs correct data type and sets trigger to {} on "document.write" events', () => { + it('constructs correct data type on "document.write" events', () => { const testFunction = functions.handler.firestore.document.onWrite( (change, context) => { expect(change.before.data()).to.deep.equal({ @@ -332,7 +296,6 @@ describe('Firestore Functions', () => { return true; // otherwise will get warning about returning undefined } ); - expect(testFunction.__trigger).to.deep.equal({}); const event = constructEvent( createOldValue(), createValue(), @@ -341,7 +304,7 @@ describe('Firestore Functions', () => { return testFunction(event.data, event.context); }).timeout(5000); - it('constructs correct data type and sets trigger to {} on "document.create" events', () => { + it('constructs correct data type on "document.create" events', () => { const testFunction = functions.handler.firestore.document.onCreate( (data, context) => { expect(data.data()).to.deep.equal({ key1: true, key2: 123 }); @@ -349,12 +312,11 @@ describe('Firestore Functions', () => { return true; // otherwise will get warning about returning undefined } ); - expect(testFunction.__trigger).to.deep.equal({}); const event = constructEvent({}, createValue(), 'document.create'); return testFunction(event.data, event.context); }).timeout(5000); - it('constructs correct data type and sets trigger to {} on "document.update" events', () => { + it('constructs correct data type on "document.update" events', () => { const testFunction = functions.handler.firestore.document.onUpdate( (change) => { expect(change.before.data()).to.deep.equal({ @@ -367,7 +329,6 @@ describe('Firestore Functions', () => { return true; // otherwise will get warning about returning undefined } ); - expect(testFunction.__trigger).to.deep.equal({}); const event = constructEvent( createOldValue(), createValue(), @@ -376,7 +337,7 @@ describe('Firestore Functions', () => { return testFunction(event.data, event.context); }).timeout(5000); - it('constructs correct data type and sets trigger to {} on "document.delete" events', () => { + it('constructs correct data type on "document.delete" events', () => { const testFunction = functions.handler.firestore.document.onDelete( (data, context) => { expect(data.data()).to.deep.equal({ key1: false, key2: 111 }); @@ -385,7 +346,6 @@ describe('Firestore Functions', () => { } ); const event = constructEvent(createOldValue(), {}, 'document.delete'); - expect(testFunction.__trigger).to.deep.equal({}); return testFunction(event.data, event.context); }).timeout(5000); }); diff --git a/spec/v1/providers/https.spec.ts b/spec/v1/providers/https.spec.ts index 7046ad25e..b1a9cfa6b 100644 --- a/spec/v1/providers/https.spec.ts +++ b/spec/v1/providers/https.spec.ts @@ -22,8 +22,8 @@ import { expect } from 'chai'; -import * as functions from '../../../src/index'; -import * as https from '../../../src/providers/https'; +import * as functions from '../../../src/v1'; +import * as https from '../../../src/v1/providers/https'; import { expectedResponseHeaders, MockRequest, @@ -36,7 +36,6 @@ describe('CloudHttpsBuilder', () => { const result = https.onRequest((req, resp) => { resp.send(200); }); - expect(result.__trigger).to.deep.equal({ httpsTrigger: {} }); expect(result.__endpoint).to.deep.equal({ platform: 'gcfv1', httpsTrigger: {}, @@ -53,11 +52,6 @@ describe('CloudHttpsBuilder', () => { }) .https.onRequest(() => null); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__trigger.httpsTrigger.invoker).to.deep.equal(['private']); - expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); @@ -72,7 +66,6 @@ describe('handler namespace', () => { const result = functions.handler.https.onRequest((req, res) => { res.send(200); }); - expect(result.__trigger).to.deep.equal({}); expect(result.__endpoint).to.be.undefined; }); }); @@ -80,7 +73,6 @@ describe('handler namespace', () => { describe('#onCall', () => { it('should return an empty trigger', () => { const result = functions.handler.https.onCall(() => null); - expect(result.__trigger).to.deep.equal({}); expect(result.__endpoint).to.be.undefined; }); }); @@ -92,11 +84,6 @@ describe('#onCall', () => { return 'response'; }); - expect(result.__trigger).to.deep.equal({ - httpsTrigger: {}, - labels: { 'deployment-callable': 'true' }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv1', callableTrigger: {}, @@ -113,10 +100,6 @@ describe('#onCall', () => { }) .https.onCall(() => null); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); diff --git a/spec/v1/providers/pubsub.spec.ts b/spec/v1/providers/pubsub.spec.ts index 5547515ab..1809c84ec 100644 --- a/spec/v1/providers/pubsub.spec.ts +++ b/spec/v1/providers/pubsub.spec.ts @@ -21,9 +21,9 @@ // SOFTWARE. import { expect } from 'chai'; -import { Event } from '../../../src/index'; -import * as functions from '../../../src/index'; -import * as pubsub from '../../../src/providers/pubsub'; +import { Event } from '../../../src/v1'; +import * as functions from '../../../src/v1'; +import * as pubsub from '../../../src/v1/providers/pubsub'; describe('Pubsub Functions', () => { describe('pubsub.Message', () => { @@ -82,10 +82,6 @@ describe('Pubsub Functions', () => { .pubsub.topic('toppy') .onPublish(() => null); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); @@ -96,14 +92,6 @@ describe('Pubsub Functions', () => { // Pick up project from process.env.GCLOUD_PROJECT const result = pubsub.topic('toppy').onPublish(() => null); - expect(result.__trigger).to.deep.equal({ - eventTrigger: { - eventType: 'google.pubsub.topic.publish', - resource: 'projects/project1/topics/toppy', - service: 'pubsub.googleapis.com', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv1', eventTrigger: { @@ -165,10 +153,6 @@ describe('Pubsub Functions', () => { .schedule('every 5 minutes') .onRun((context) => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - }); - expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', }); @@ -180,11 +164,6 @@ describe('Pubsub Functions', () => { .timeZone('America/New_York') .onRun((context) => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - timeZone: 'America/New_York', - }); - expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', timeZone: 'America/New_York', @@ -204,14 +183,6 @@ describe('Pubsub Functions', () => { .retryConfig(retryConfig) .onRun(() => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - retryConfig, - }); - expect(result.__trigger.labels).to.deep.equal({ - 'deployment-scheduled': 'true', - }); - expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', retryConfig, @@ -236,15 +207,6 @@ describe('Pubsub Functions', () => { .retryConfig(retryConfig) .onRun(() => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - retryConfig, - timeZone: 'America/New_York', - }); - expect(result.__trigger.labels).to.deep.equal({ - 'deployment-scheduled': 'true', - }); - expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', retryConfig, @@ -263,12 +225,6 @@ describe('Pubsub Functions', () => { }) .pubsub.schedule('every 5 minutes') .onRun(() => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - }); - expect(result.__trigger.regions).to.deep.equal(['us-east1']); - expect(result.__trigger.availableMemoryMb).to.deep.equal(256); - expect(result.__trigger.timeout).to.deep.equal('90s'); expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', @@ -288,13 +244,6 @@ describe('Pubsub Functions', () => { .pubsub.schedule('every 5 minutes') .timeZone('America/New_York') .onRun(() => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - timeZone: 'America/New_York', - }); - expect(result.__trigger.regions).to.deep.equal(['us-east1']); - expect(result.__trigger.availableMemoryMb).to.deep.equal(256); - expect(result.__trigger.timeout).to.deep.equal('90s'); expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', @@ -322,16 +271,6 @@ describe('Pubsub Functions', () => { .pubsub.schedule('every 5 minutes') .retryConfig(retryConfig) .onRun(() => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - retryConfig, - }); - expect(result.__trigger.labels).to.deep.equal({ - 'deployment-scheduled': 'true', - }); - expect(result.__trigger.regions).to.deep.equal(['us-east1']); - expect(result.__trigger.availableMemoryMb).to.deep.equal(256); - expect(result.__trigger.timeout).to.deep.equal('90s'); expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', @@ -360,17 +299,6 @@ describe('Pubsub Functions', () => { .timeZone('America/New_York') .retryConfig(retryConfig) .onRun(() => null); - expect(result.__trigger.schedule).to.deep.equal({ - schedule: 'every 5 minutes', - timeZone: 'America/New_York', - retryConfig, - }); - expect(result.__trigger.labels).to.deep.equal({ - 'deployment-scheduled': 'true', - }); - expect(result.__trigger.regions).to.deep.equal(['us-east1']); - expect(result.__trigger.availableMemoryMb).to.deep.equal(256); - expect(result.__trigger.timeout).to.deep.equal('90s'); expect(result.__endpoint.scheduleTrigger).to.deep.equal({ schedule: 'every 5 minutes', @@ -389,7 +317,6 @@ describe('Pubsub Functions', () => { describe('#topic', () => { it('should return an empty trigger', () => { const result = functions.handler.pubsub.topic.onPublish(() => null); - expect(result.__trigger).to.deep.equal({}); expect(result.__endpoint).to.be.undefined; }); @@ -435,7 +362,7 @@ describe('Pubsub Functions', () => { describe('#schedule', () => { it('should return an empty trigger', () => { const result = functions.handler.pubsub.schedule.onRun(() => null); - expect(result.__trigger).to.deep.equal({}); + expect(result.__endpoint).to.be.undefined; }); it('should return a handler with a proper event context', () => { const raw = new Buffer('{"hello":"world"}', 'utf8').toString( @@ -470,18 +397,12 @@ describe('Pubsub Functions', () => { }); describe('process.env.GCLOUD_PROJECT not set', () => { - it('should not throw if __trigger is not accessed', () => { + it('should not throw if __endpoint is not accessed', () => { expect(() => pubsub.topic('toppy').onPublish(() => null)).to.not.throw( Error ); }); - it('should throw when trigger is accessed', () => { - expect( - () => pubsub.topic('toppy').onPublish(() => null).__trigger - ).to.throw(Error); - }); - it('should throw when endpoint is accessed', () => { expect( () => pubsub.topic('toppy').onPublish(() => null).__endpoint diff --git a/spec/v1/providers/remoteConfig.spec.ts b/spec/v1/providers/remoteConfig.spec.ts index f3fde2043..f0367916e 100644 --- a/spec/v1/providers/remoteConfig.spec.ts +++ b/spec/v1/providers/remoteConfig.spec.ts @@ -21,13 +21,13 @@ // SOFTWARE. import { expect } from 'chai'; +import * as functions from '../../../src/v1'; import { CloudFunction, Event, EventContext, -} from '../../../src/cloud-functions'; -import * as functions from '../../../src/index'; -import * as remoteConfig from '../../../src/providers/remoteConfig'; +} from '../../../src/v1/cloud-functions'; +import * as remoteConfig from '../../../src/v1/providers/remoteConfig'; describe('RemoteConfig Functions', () => { function constructVersion() { @@ -56,14 +56,6 @@ describe('RemoteConfig Functions', () => { it('should have the correct trigger', () => { const cloudFunction = remoteConfig.onUpdate(() => null); - expect(cloudFunction.__trigger).to.deep.equal({ - eventTrigger: { - resource: 'projects/project1', - eventType: 'google.firebase.remoteconfig.update', - service: 'firebaseremoteconfig.googleapis.com', - }, - }); - expect(cloudFunction.__endpoint).to.deep.equal({ platform: 'gcfv1', eventTrigger: { @@ -86,10 +78,6 @@ describe('RemoteConfig Functions', () => { }) .remoteConfig.onUpdate(() => null); - expect(cloudFunction.__trigger.regions).to.deep.equal(['us-east1']); - expect(cloudFunction.__trigger.availableMemoryMb).to.deep.equal(256); - expect(cloudFunction.__trigger.timeout).to.deep.equal('90s'); - expect(cloudFunction.__endpoint.region).to.deep.equal(['us-east1']); expect(cloudFunction.__endpoint.availableMemoryMb).to.deep.equal(256); expect(cloudFunction.__endpoint.timeoutSeconds).to.deep.equal(90); @@ -143,7 +131,6 @@ describe('RemoteConfig Functions', () => { () => null ); - expect(cloudFunction.__trigger).to.deep.equal({}); expect(cloudFunction.__endpoint).to.be.undefined; }); diff --git a/spec/v1/providers/storage.spec.ts b/spec/v1/providers/storage.spec.ts index d96b131b9..12ff2b3bb 100644 --- a/spec/v1/providers/storage.spec.ts +++ b/spec/v1/providers/storage.spec.ts @@ -21,23 +21,13 @@ // SOFTWARE. import { expect } from 'chai'; -import { Event, EventContext } from '../../../src'; -import * as functions from '../../../src'; -import * as config from '../../../src/config'; -import * as storage from '../../../src/providers/storage'; +import * as config from '../../../src/common/config'; +import { Event, EventContext } from '../../../src/v1'; +import * as functions from '../../../src/v1'; +import * as storage from '../../../src/v1/providers/storage'; describe('Storage Functions', () => { describe('ObjectBuilder', () => { - function expectedTrigger(bucket: string, eventType: string) { - return { - eventTrigger: { - resource: `projects/_/buckets/${bucket}`, - eventType: `google.storage.object.${eventType}`, - service: 'storage.googleapis.com', - }, - }; - } - function expectedEndpoint(bucket: string, eventType: string) { return { platform: 'gcfv1', @@ -55,13 +45,13 @@ describe('Storage Functions', () => { const defaultBucket = 'bucket'; before(() => { - (config as any).firebaseConfigCache = { + config.resetCache({ storageBucket: defaultBucket, - }; + }); }); after(() => { - (config as any).firebaseConfigcache = null; + config.resetCache(); }); it('should allow both region and runtime options to be set', () => { @@ -74,10 +64,6 @@ describe('Storage Functions', () => { .storage.object() .onArchive(() => null); - expect(fn.__trigger.regions).to.deep.equal(['us-east1']); - expect(fn.__trigger.availableMemoryMb).to.deep.equal(256); - expect(fn.__trigger.timeout).to.deep.equal('90s'); - expect(fn.__endpoint.region).to.deep.equal(['us-east1']); expect(fn.__endpoint.availableMemoryMb).to.deep.equal(256); expect(fn.__endpoint.timeoutSeconds).to.deep.equal(90); @@ -90,10 +76,6 @@ describe('Storage Functions', () => { .object() .onArchive(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger('bucky', 'archive') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'archive') ); @@ -102,10 +84,6 @@ describe('Storage Functions', () => { it('should use the default bucket when none is provided', () => { const cloudFunction = storage.object().onArchive(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(defaultBucket, 'archive') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(defaultBucket, 'archive') ); @@ -118,24 +96,12 @@ describe('Storage Functions', () => { ); const result = subjectQualified.onArchive(() => null); - expect(result.__trigger).to.deep.equal( - expectedTrigger('bucky', 'archive') - ); - expect(result.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'archive') ); }); it('should throw with improperly formatted buckets', () => { - expect( - () => - storage - .bucket('bad/bucket/format') - .object() - .onArchive(() => null).__trigger - ).to.throw(Error); - expect( () => storage @@ -181,10 +147,6 @@ describe('Storage Functions', () => { .object() .onDelete(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger('bucky', 'delete') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'delete') ); @@ -193,10 +155,6 @@ describe('Storage Functions', () => { it('should use the default bucket when none is provided', () => { const cloudFunction = storage.object().onDelete(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(defaultBucket, 'delete') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(defaultBucket, 'delete') ); @@ -209,10 +167,6 @@ describe('Storage Functions', () => { ); const result = subjectQualified.onDelete(() => null); - expect(result.__trigger).to.deep.equal( - expectedTrigger('bucky', 'delete') - ); - expect(result.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'delete') ); @@ -224,8 +178,6 @@ describe('Storage Functions', () => { .object() .onDelete(() => null); - expect(() => fn.__trigger).to.throw(Error); - expect(() => fn.__endpoint).to.throw(Error); }); @@ -265,10 +217,6 @@ describe('Storage Functions', () => { .object() .onFinalize(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger('bucky', 'finalize') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'finalize') ); @@ -277,10 +225,6 @@ describe('Storage Functions', () => { it('should use the default bucket when none is provided', () => { const cloudFunction = storage.object().onFinalize(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(defaultBucket, 'finalize') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(defaultBucket, 'finalize') ); @@ -293,10 +237,6 @@ describe('Storage Functions', () => { ); const result = subjectQualified.onFinalize(() => null); - expect(result.__trigger).to.deep.equal( - expectedTrigger('bucky', 'finalize') - ); - expect(result.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'finalize') ); @@ -308,8 +248,6 @@ describe('Storage Functions', () => { .object() .onFinalize(() => null); - expect(() => fn.__trigger).to.throw(Error); - expect(() => fn.__endpoint).to.throw(Error); }); @@ -349,10 +287,6 @@ describe('Storage Functions', () => { .object() .onMetadataUpdate(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger('bucky', 'metadataUpdate') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'metadataUpdate') ); @@ -361,10 +295,6 @@ describe('Storage Functions', () => { it('should use the default bucket when none is provided', () => { const cloudFunction = storage.object().onMetadataUpdate(() => null); - expect(cloudFunction.__trigger).to.deep.equal( - expectedTrigger(defaultBucket, 'metadataUpdate') - ); - expect(cloudFunction.__endpoint).to.deep.equal( expectedEndpoint(defaultBucket, 'metadataUpdate') ); @@ -377,10 +307,6 @@ describe('Storage Functions', () => { ); const result = subjectQualified.onMetadataUpdate(() => null); - expect(result.__trigger).to.deep.equal( - expectedTrigger('bucky', 'metadataUpdate') - ); - expect(result.__endpoint).to.deep.equal( expectedEndpoint('bucky', 'metadataUpdate') ); @@ -392,7 +318,6 @@ describe('Storage Functions', () => { .object() .onMetadataUpdate(() => null); - expect(() => fn.__trigger).to.throw(Error); expect(() => fn.__endpoint).to.throw(Error); }); @@ -443,7 +368,6 @@ describe('Storage Functions', () => { () => null ); - expect(cloudFunction.__trigger).to.deep.equal({}); expect(cloudFunction.__endpoint).to.be.undefined; }); @@ -484,7 +408,6 @@ describe('Storage Functions', () => { () => null ); - expect(cloudFunction.__trigger).to.deep.equal({}); expect(cloudFunction.__endpoint).to.be.undefined; }); @@ -525,7 +448,6 @@ describe('Storage Functions', () => { () => null ); - expect(cloudFunction.__trigger).to.deep.equal({}); expect(cloudFunction.__endpoint).to.be.undefined; }); @@ -566,7 +488,6 @@ describe('Storage Functions', () => { () => null ); - expect(cloudFunction.__trigger).to.deep.equal({}); expect(cloudFunction.__endpoint).to.be.undefined; }); @@ -608,16 +529,10 @@ describe('Storage Functions', () => { delete process.env.FIREBASE_CONFIG; }); - it('should not throw if __trigger is not accessed', () => { + it('should not throw if __endpoint is not accessed', () => { expect(() => storage.object().onArchive(() => null)).to.not.throw(Error); }); - it('should throw when trigger is accessed', () => { - expect(() => storage.object().onArchive(() => null).__trigger).to.throw( - Error - ); - }); - it('should throw when endpoint is accessed', () => { expect(() => storage.object().onArchive(() => null).__endpoint).to.throw( Error diff --git a/spec/v1/providers/tasks.spec.ts b/spec/v1/providers/tasks.spec.ts index 20f8c8e00..6382e00a4 100644 --- a/spec/v1/providers/tasks.spec.ts +++ b/spec/v1/providers/tasks.spec.ts @@ -22,8 +22,8 @@ import { expect } from 'chai'; -import * as functions from '../../../src'; -import { taskQueue } from '../../../src/providers/tasks'; +import * as functions from '../../../src/v1'; +import { taskQueue } from '../../../src/v1/providers/tasks'; import { MockRequest } from '../../fixtures/mockrequest'; import { runHandler } from '../../helper'; @@ -44,23 +44,6 @@ describe('#onDispatch', () => { invoker: 'private', }).onDispatch(() => {}); - expect(result.__trigger).to.deep.equal({ - taskQueueTrigger: { - rateLimits: { - maxConcurrentDispatches: 30, - maxDispatchesPerSecond: 40, - }, - retryConfig: { - maxAttempts: 5, - maxRetrySeconds: 10, - maxBackoffSeconds: 20, - maxDoublings: 3, - minBackoffSeconds: 5, - }, - invoker: ['private'], - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv1', taskQueueTrigger: { @@ -90,17 +73,6 @@ describe('#onDispatch', () => { .tasks.taskQueue({ retryConfig: { maxAttempts: 5 } }) .onDispatch(() => null); - expect(fn.__trigger).to.deep.equal({ - regions: ['us-east1'], - availableMemoryMb: 256, - timeout: '90s', - taskQueueTrigger: { - retryConfig: { - maxAttempts: 5, - }, - }, - }); - expect(fn.__endpoint).to.deep.equal({ platform: 'gcfv1', region: ['us-east1'], @@ -160,7 +132,6 @@ describe('#onDispatch', () => { describe('handler namespace', () => { it('should return an empty trigger', () => { const result = functions.handler.tasks.taskQueue.onDispatch(() => null); - expect(result.__trigger).to.deep.equal({}); expect(result.__endpoint).to.be.undefined; }); }); diff --git a/spec/v1/providers/testLab.spec.ts b/spec/v1/providers/testLab.spec.ts index b3ba22d7f..be2922e4e 100644 --- a/spec/v1/providers/testLab.spec.ts +++ b/spec/v1/providers/testLab.spec.ts @@ -22,7 +22,7 @@ import { expect } from 'chai'; -import * as testLab from '../../../src/providers/testLab'; +import * as testLab from '../../../src/v1/providers/testLab'; describe('Test Lab Functions', () => { describe('#onComplete', () => { @@ -38,14 +38,6 @@ describe('Test Lab Functions', () => { it('should return a trigger/endpoint with appropriate values', () => { const func = testLab.testMatrix().onComplete(() => null); - expect(func.__trigger).to.deep.equal({ - eventTrigger: { - service: 'testing.googleapis.com', - eventType: 'google.testing.testMatrix.complete', - resource: 'projects/project1/testMatrices/{matrix}', - }, - }); - expect(func.__endpoint).to.deep.equal({ platform: 'gcfv1', eventTrigger: { @@ -157,18 +149,12 @@ describe('Test Lab Functions', () => { }); describe('process.env.GCLOUD_PROJECT not set', () => { - it('should not throw if trigger is not accessed', () => { + it('should not throw if __endpoint is not accessed', () => { expect(() => testLab.testMatrix().onComplete(() => null)).to.not.throw( Error ); }); - it('should throw when trigger is accessed', () => { - expect( - () => testLab.testMatrix().onComplete(() => null).__trigger - ).to.throw(Error); - }); - it('should throw when endpoint is accessed', () => { expect( () => testLab.testMatrix().onComplete(() => null).__endpoint diff --git a/spec/v1/utils.spec.ts b/spec/v1/utils.spec.ts index db749ca5d..d79445d55 100644 --- a/spec/v1/utils.spec.ts +++ b/spec/v1/utils.spec.ts @@ -21,7 +21,7 @@ // SOFTWARE. import { expect } from 'chai'; -import { applyChange } from '../../src/utils'; +import { applyChange } from '../../src/common/utilities/utils'; describe('utils', () => { describe('.applyChange(from: any, to: any): any', () => { diff --git a/spec/v2/providers/database.spec.ts b/spec/v2/providers/database.spec.ts index 58d4285ab..34a20bbf6 100644 --- a/spec/v2/providers/database.spec.ts +++ b/spec/v2/providers/database.spec.ts @@ -21,7 +21,7 @@ // SOFTWARE. import { expect } from 'chai'; -import { PathPattern } from '../../../src/utilities/path-pattern'; +import { PathPattern } from '../../../src/common/utilities/path-pattern'; import * as database from '../../../src/v2/providers/database'; const RAW_RTDB_EVENT: database.RawRTDBCloudEvent = { diff --git a/spec/v2/providers/fixtures.ts b/spec/v2/providers/fixtures.ts index f330efed1..84ab2344c 100644 --- a/spec/v2/providers/fixtures.ts +++ b/spec/v2/providers/fixtures.ts @@ -1,5 +1,4 @@ import { ManifestEndpoint } from '../../../src/runtime/manifest'; -import { TriggerAnnotation } from '../../../src/v2/core'; import * as options from '../../../src/v2/options'; export const FULL_OPTIONS: options.GlobalOptions = { @@ -20,24 +19,6 @@ export const FULL_OPTIONS: options.GlobalOptions = { secrets: ['MY_SECRET'], }; -export const FULL_TRIGGER: TriggerAnnotation = { - platform: 'gcfv2', - regions: ['us-west1'], - availableMemoryMb: 512, - timeout: '60s', - minInstances: 1, - maxInstances: 3, - concurrency: 20, - vpcConnector: 'aConnector', - vpcConnectorEgressSettings: 'ALL_TRAFFIC', - serviceAccountEmail: 'root@aProject.iam.gserviceaccount.com', - ingressSettings: 'ALLOW_ALL', - labels: { - hello: 'world', - }, - secrets: ['MY_SECRET'], -}; - export const FULL_ENDPOINT: ManifestEndpoint = { platform: 'gcfv2', region: ['us-west1'], diff --git a/spec/v2/providers/https.spec.ts b/spec/v2/providers/https.spec.ts index 65e573849..882c7e854 100644 --- a/spec/v2/providers/https.spec.ts +++ b/spec/v2/providers/https.spec.ts @@ -31,7 +31,7 @@ import { MockRequest, } from '../../fixtures/mockrequest'; import { runHandler } from '../../helper'; -import { FULL_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from './fixtures'; +import { FULL_ENDPOINT, FULL_OPTIONS } from './fixtures'; describe('onRequest', () => { beforeEach(() => { @@ -48,14 +48,6 @@ describe('onRequest', () => { res.send(200); }); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - httpsTrigger: { - allowInsecure: false, - }, - labels: {}, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', httpsTrigger: {}, @@ -75,15 +67,6 @@ describe('onRequest', () => { } ); - expect(result.__trigger).to.deep.equal({ - ...FULL_TRIGGER, - httpsTrigger: { - allowInsecure: false, - invoker: ['service-account1@', 'service-account2@'], - }, - regions: ['us-west1', 'us-central1'], - }); - expect(result.__endpoint).to.deep.equal({ ...FULL_ENDPOINT, httpsTrigger: { @@ -112,18 +95,6 @@ describe('onRequest', () => { } ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - httpsTrigger: { - allowInsecure: false, - invoker: ['private'], - }, - concurrency: 20, - minInstances: 3, - regions: ['us-west1', 'us-central1'], - labels: {}, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', httpsTrigger: { @@ -233,16 +204,6 @@ describe('onCall', () => { it('should return a minimal trigger/endpoint with appropriate values', () => { const result = https.onCall((request) => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - httpsTrigger: { - allowInsecure: false, - }, - labels: { - 'deployment-callable': 'true', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', callableTrigger: {}, @@ -253,17 +214,6 @@ describe('onCall', () => { it('should create a complex trigger/endpoint with appropriate values', () => { const result = https.onCall(FULL_OPTIONS, (request) => 42); - expect(result.__trigger).to.deep.equal({ - ...FULL_TRIGGER, - httpsTrigger: { - allowInsecure: false, - }, - labels: { - ...FULL_TRIGGER.labels, - 'deployment-callable': 'true', - }, - }); - expect(result.__endpoint).to.deep.equal({ ...FULL_ENDPOINT, callableTrigger: {}, @@ -285,19 +235,6 @@ describe('onCall', () => { (request) => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - httpsTrigger: { - allowInsecure: false, - }, - concurrency: 20, - minInstances: 3, - regions: ['us-west1', 'us-central1'], - labels: { - 'deployment-callable': 'true', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', callableTrigger: {}, diff --git a/spec/v2/providers/pubsub.spec.ts b/spec/v2/providers/pubsub.spec.ts index 395dadace..ec4dddbae 100644 --- a/spec/v2/providers/pubsub.spec.ts +++ b/spec/v2/providers/pubsub.spec.ts @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { CloudEvent } from '../../../src/v2/core'; import * as options from '../../../src/v2/options'; import * as pubsub from '../../../src/v2/providers/pubsub'; -import { FULL_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from './fixtures'; +import { FULL_ENDPOINT, FULL_OPTIONS } from './fixtures'; const EVENT_TRIGGER = { eventType: 'google.cloud.pubsub.topic.v1.messagePublished', @@ -31,12 +31,6 @@ describe('onMessagePublished', () => { it('should return a minimal trigger/endpoint with appropriate values', () => { const result = pubsub.onMessagePublished('topic', () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - eventTrigger: EVENT_TRIGGER, - labels: {}, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', eventTrigger: ENDPOINT_EVENT_TRIGGER, @@ -50,11 +44,6 @@ describe('onMessagePublished', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - ...FULL_TRIGGER, - eventTrigger: EVENT_TRIGGER, - }); - expect(result.__endpoint).to.deep.equal({ ...FULL_ENDPOINT, eventTrigger: ENDPOINT_EVENT_TRIGGER, @@ -77,15 +66,6 @@ describe('onMessagePublished', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - concurrency: 20, - minInstances: 3, - regions: ['us-west1'], - labels: {}, - eventTrigger: EVENT_TRIGGER, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', concurrency: 20, @@ -107,15 +87,6 @@ describe('onMessagePublished', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - minInstances: 3, - regions: ['us-west1'], - labels: {}, - eventTrigger: EVENT_TRIGGER, - failurePolicy: { retry: true }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', minInstances: 3, diff --git a/spec/v2/providers/storage.spec.ts b/spec/v2/providers/storage.spec.ts index 4f5221b6a..4122380b5 100644 --- a/spec/v2/providers/storage.spec.ts +++ b/spec/v2/providers/storage.spec.ts @@ -1,14 +1,8 @@ import { expect } from 'chai'; -import * as sinon from 'sinon'; -import * as config from '../../../src/config'; +import * as config from '../../../src/common/config'; import * as options from '../../../src/v2/options'; import * as storage from '../../../src/v2/providers/storage'; -import { FULL_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from './fixtures'; - -const EVENT_TRIGGER = { - eventType: 'event-type', - resource: 'some-bucket', -}; +import { FULL_ENDPOINT, FULL_OPTIONS } from './fixtures'; const ENDPOINT_EVENT_TRIGGER = { eventType: 'event-type', @@ -29,25 +23,21 @@ const SPECIFIC_BUCKET_EVENT_FILTER = { describe('v2/storage', () => { describe('getOptsAndBucket', () => { it('should return the default bucket with empty opts', () => { - const configStub = sinon - .stub(config, 'firebaseConfig') - .returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const [opts, bucket] = storage.getOptsAndBucket({}); - configStub.restore(); + config.resetCache(); expect(opts).to.deep.equal({}); expect(bucket).to.eq('default-bucket'); }); it('should return the default bucket with opts param', () => { - const configStub = sinon - .stub(config, 'firebaseConfig') - .returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const [opts, bucket] = storage.getOptsAndBucket({ region: 'us-west1' }); - configStub.restore(); + config.resetCache(); expect(opts).to.deep.equal({ region: 'us-west1' }); expect(bucket).to.eq('default-bucket'); }); @@ -71,28 +61,19 @@ describe('v2/storage', () => { }); describe('onOperation', () => { - let configStub: sinon.SinonStub; - beforeEach(() => { process.env.GCLOUD_PROJECT = 'aProject'; - configStub = sinon.stub(config, 'firebaseConfig'); }); afterEach(() => { options.setGlobalOptions({}); + config.resetCache(); delete process.env.GCLOUD_PROJECT; - configStub.restore(); }); it('should create a minimal trigger/endpoint with bucket', () => { const result = storage.onOperation('event-type', 'some-bucket', () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: EVENT_TRIGGER, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -101,7 +82,7 @@ describe('v2/storage', () => { }); it('should create a minimal trigger/endpoint with opts', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onOperation( 'event-type', @@ -109,16 +90,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...EVENT_TRIGGER, - resource: 'default-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -137,12 +108,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: EVENT_TRIGGER, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -160,11 +125,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - ...FULL_TRIGGER, - eventTrigger: EVENT_TRIGGER, - }); - expect(result.__endpoint).to.deep.equal({ ...FULL_ENDPOINT, eventTrigger: ENDPOINT_EVENT_TRIGGER, @@ -188,15 +148,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - concurrency: 20, - minInstances: 3, - regions: ['us-west1'], - labels: {}, - eventTrigger: EVENT_TRIGGER, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', concurrency: 20, @@ -209,38 +160,20 @@ describe('v2/storage', () => { }); describe('onObjectArchived', () => { - const ARCHIVED_TRIGGER = { - ...EVENT_TRIGGER, - eventType: storage.archivedEvent, - }; const ENDPOINT_ARCHIVED_TRIGGER = { ...ENDPOINT_EVENT_TRIGGER, eventType: storage.archivedEvent, }; - let configStub: sinon.SinonStub; - - beforeEach(() => { - configStub = sinon.stub(config, 'firebaseConfig'); - }); afterEach(() => { - configStub.restore(); + config.resetCache(); }); it('should accept only handler', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectArchived(() => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...ARCHIVED_TRIGGER, - resource: 'default-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -254,15 +187,6 @@ describe('v2/storage', () => { it('should accept bucket and handler', () => { const result = storage.onObjectArchived('my-bucket', () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...ARCHIVED_TRIGGER, - resource: 'my-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -279,16 +203,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...ARCHIVED_TRIGGER, - resource: 'my-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -301,20 +215,10 @@ describe('v2/storage', () => { }); it('should accept opts and handler, default bucket', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectArchived({ region: 'us-west1' }, () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...ARCHIVED_TRIGGER, - resource: 'default-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -328,38 +232,20 @@ describe('v2/storage', () => { }); describe('onObjectFinalized', () => { - const FINALIZED_TRIGGER = { - ...EVENT_TRIGGER, - eventType: storage.finalizedEvent, - }; const ENDPOINT_FINALIZED_TRIGGER = { ...ENDPOINT_EVENT_TRIGGER, eventType: storage.finalizedEvent, }; - let configStub: sinon.SinonStub; - - beforeEach(() => { - configStub = sinon.stub(config, 'firebaseConfig'); - }); afterEach(() => { - configStub.restore(); + config.resetCache(); }); it('should accept only handler', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectFinalized(() => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...FINALIZED_TRIGGER, - resource: 'default-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -373,15 +259,6 @@ describe('v2/storage', () => { it('should accept bucket and handler', () => { const result = storage.onObjectFinalized('my-bucket', () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...FINALIZED_TRIGGER, - resource: 'my-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -398,16 +275,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...FINALIZED_TRIGGER, - resource: 'my-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -420,23 +287,13 @@ describe('v2/storage', () => { }); it('should accept opts and handler, default bucket', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectFinalized( { region: 'us-west1' }, () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...FINALIZED_TRIGGER, - resource: 'default-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -450,38 +307,20 @@ describe('v2/storage', () => { }); describe('onObjectDeleted', () => { - const DELETED_TRIGGER = { - ...EVENT_TRIGGER, - eventType: storage.deletedEvent, - }; const ENDPOINT_DELETED_TRIGGER = { ...ENDPOINT_EVENT_TRIGGER, eventType: storage.deletedEvent, }; - let configStub: sinon.SinonStub; - - beforeEach(() => { - configStub = sinon.stub(config, 'firebaseConfig'); - }); afterEach(() => { - configStub.restore(); + config.resetCache(); }); it('should accept only handler', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectDeleted(() => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...DELETED_TRIGGER, - resource: 'default-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -490,22 +329,11 @@ describe('v2/storage', () => { eventFilters: DEFAULT_BUCKET_EVENT_FILTER, }, }); - - configStub.restore(); }); it('should accept bucket and handler', () => { const result = storage.onObjectDeleted('my-bucket', () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...DELETED_TRIGGER, - resource: 'my-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -522,16 +350,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...DELETED_TRIGGER, - resource: 'my-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -544,20 +362,10 @@ describe('v2/storage', () => { }); it('should accept opts and handler, default bucket', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectDeleted({ region: 'us-west1' }, () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...DELETED_TRIGGER, - resource: 'default-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -571,38 +379,20 @@ describe('v2/storage', () => { }); describe('onObjectMetadataUpdated', () => { - const METADATA_TRIGGER = { - ...EVENT_TRIGGER, - eventType: storage.metadataUpdatedEvent, - }; const ENDPOINT_METADATA_TRIGGER = { ...ENDPOINT_EVENT_TRIGGER, eventType: storage.metadataUpdatedEvent, }; - let configStub: sinon.SinonStub; - - beforeEach(() => { - configStub = sinon.stub(config, 'firebaseConfig'); - }); afterEach(() => { - configStub.restore(); + config.resetCache(); }); it('should accept only handler', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectMetadataUpdated(() => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...METADATA_TRIGGER, - resource: 'default-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -611,22 +401,11 @@ describe('v2/storage', () => { eventFilters: DEFAULT_BUCKET_EVENT_FILTER, }, }); - - configStub.restore(); }); it('should accept bucket and handler', () => { const result = storage.onObjectMetadataUpdated('my-bucket', () => 42); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...METADATA_TRIGGER, - resource: 'my-bucket', - }, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -643,16 +422,6 @@ describe('v2/storage', () => { () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...METADATA_TRIGGER, - resource: 'my-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, @@ -665,23 +434,13 @@ describe('v2/storage', () => { }); it('should accept opts and handler, default bucket', () => { - configStub.returns({ storageBucket: 'default-bucket' }); + config.resetCache({ storageBucket: 'default-bucket' }); const result = storage.onObjectMetadataUpdated( { region: 'us-west1' }, () => 42 ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - labels: {}, - eventTrigger: { - ...METADATA_TRIGGER, - resource: 'default-bucket', - }, - regions: ['us-west1'], - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', labels: {}, diff --git a/spec/v2/providers/tasks.spec.ts b/spec/v2/providers/tasks.spec.ts index f0f8c9cc5..cf4ffd019 100644 --- a/spec/v2/providers/tasks.spec.ts +++ b/spec/v2/providers/tasks.spec.ts @@ -26,7 +26,7 @@ import * as options from '../../../src/v2/options'; import { onTaskDispatched, Request } from '../../../src/v2/providers/tasks'; import { MockRequest } from '../../fixtures/mockrequest'; import { runHandler } from '../../helper'; -import { FULL_ENDPOINT, FULL_OPTIONS, FULL_TRIGGER } from './fixtures'; +import { FULL_ENDPOINT, FULL_OPTIONS } from './fixtures'; describe('onTaskDispatched', () => { beforeEach(() => { @@ -41,12 +41,6 @@ describe('onTaskDispatched', () => { it('should return a minimal trigger/endpoint with appropriate values', () => { const result = onTaskDispatched(() => {}); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - taskQueueTrigger: {}, - labels: {}, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', taskQueueTrigger: {}, @@ -74,24 +68,6 @@ describe('onTaskDispatched', () => { () => {} ); - expect(result.__trigger).to.deep.equal({ - ...FULL_TRIGGER, - taskQueueTrigger: { - retryConfig: { - maxAttempts: 4, - maxRetrySeconds: 10, - maxDoublings: 3, - minBackoffSeconds: 1, - maxBackoffSeconds: 2, - }, - rateLimits: { - maxConcurrentDispatches: 5, - maxDispatchesPerSecond: 10, - }, - invoker: ['private'], - }, - }); - expect(result.__endpoint).to.deep.equal({ ...FULL_ENDPOINT, platform: 'gcfv2', @@ -127,15 +103,6 @@ describe('onTaskDispatched', () => { (request) => {} ); - expect(result.__trigger).to.deep.equal({ - platform: 'gcfv2', - taskQueueTrigger: {}, - concurrency: 20, - minInstances: 3, - regions: ['us-west1'], - labels: {}, - }); - expect(result.__endpoint).to.deep.equal({ platform: 'gcfv2', taskQueueTrigger: {}, diff --git a/src/common/app.ts b/src/common/app.ts index 4fa55961f..60bb5d064 100644 --- a/src/common/app.ts +++ b/src/common/app.ts @@ -27,7 +27,7 @@ import { getApp as getAppNamed, initializeApp, } from 'firebase-admin/app'; -import { firebaseConfig } from '../config'; +import { firebaseConfig } from './config'; const APP_NAME = '__FIREBASE_FUNCTIONS_SDK__'; diff --git a/src/common/config.ts b/src/common/config.ts new file mode 100644 index 000000000..885a0a13c --- /dev/null +++ b/src/common/config.ts @@ -0,0 +1,60 @@ +import { AppOptions } from 'firebase-admin/app'; +import { readFileSync } from 'fs'; +import * as path from 'path'; + +import * as logger from '../logger'; + +let cache: AppOptions | null = null; + +/** + * @internal + * @alpha + */ +export function resetCache(newCache: AppOptions = null) { + cache = newCache; +} + +/** + * Get the fields you need to initialize a Firebase app + * @alpha + */ +export function firebaseConfig(): AppOptions | null { + if (cache) { + return cache; + } + + let env = process.env.FIREBASE_CONFIG; + if (env) { + // Firebase Tools will always use a JSON blob in prod, but docs + // explicitly state that the user can set the env to a file: + // https://firebase.google.com/docs/admin/setup#initialize-without-parameters + if (!env.startsWith('{')) { + env = readFileSync(path.join(process.env.PWD, env)).toString('utf8'); + } + + cache = JSON.parse(env); + return cache; + } + + if (process.env.GCLOUD_PROJECT) { + logger.warn( + 'Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail' + ); + cache = { + databaseURL: + process.env.DATABASE_URL || + `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`, + storageBucket: + process.env.STORAGE_BUCKET_URL || + `${process.env.GCLOUD_PROJECT}.appspot.com`, + projectId: process.env.GCLOUD_PROJECT, + }; + return cache; + } else { + logger.warn( + 'Warning, FIREBASE_CONFIG and GCLOUD_PROJECT environment variables are missing. Initializing firebase-admin will fail' + ); + } + + return null; +} diff --git a/src/common/encoding.ts b/src/common/encoding.ts index 554c5fcb1..0e5724df3 100644 --- a/src/common/encoding.ts +++ b/src/common/encoding.ts @@ -22,17 +22,6 @@ // Copied from firebase-tools/src/gcp/proto -/** - * A type alias used to annotate interfaces as using a google.protobuf.Duration. - * This type is parsed/encoded as a string of seconds + the "s" prefix. - */ -export type Duration = string; - -/** Get a google.protobuf.Duration for a number of seconds. */ -export function durationFromSeconds(s: number): Duration { - return `${s}s`; -} - /** * Utility function to help copy fields from type A to B. * As a safety net, catches typos or fields that aren't named the same @@ -72,27 +61,6 @@ export function convertIfPresent( dest[destField] = converter(src[srcField]); } -export function serviceAccountFromShorthand( - serviceAccount: string -): string | null { - if (serviceAccount === 'default') { - return null; - } else if (serviceAccount.endsWith('@')) { - if (!process.env.GCLOUD_PROJECT) { - throw new Error( - `Unable to determine email for service account '${serviceAccount}' because process.env.GCLOUD_PROJECT is not set.` - ); - } - return `${serviceAccount}${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`; - } else if (serviceAccount.includes('@')) { - return serviceAccount; - } else { - throw new Error( - `Invalid option for serviceAccount: '${serviceAccount}'. Valid options are 'default', a service account email, or '{serviceAccountName}@'` - ); - } -} - export function convertInvoker(invoker: string | string[]): string[] { if (typeof invoker === 'string') { invoker = [invoker]; diff --git a/src/common/providers/database.ts b/src/common/providers/database.ts index d7fc84449..d9ff0a748 100644 --- a/src/common/providers/database.ts +++ b/src/common/providers/database.ts @@ -22,8 +22,8 @@ import { App } from 'firebase-admin/app'; import * as database from 'firebase-admin/database'; -import { firebaseConfig } from '../../config'; -import { joinPath, pathParts } from '../../utilities/path'; +import { firebaseConfig } from '../../common/config'; +import { joinPath, pathParts } from '../../common/utilities/path'; /** * Interface representing a Firebase Realtime database data snapshot. diff --git a/src/common/providers/identity.ts b/src/common/providers/identity.ts index 0650d9266..315bde8cd 100644 --- a/src/common/providers/identity.ts +++ b/src/common/providers/identity.ts @@ -22,8 +22,8 @@ import * as express from 'express'; import * as auth from 'firebase-admin/auth'; -import { logger } from '../..'; -import { EventContext } from '../../cloud-functions'; +import * as logger from '../../logger'; +import { EventContext } from '../../v1/cloud-functions'; import { getApp } from '../app'; import { isDebugFeatureEnabled } from '../debug'; import { HttpsError, unsafeDecodeToken } from './https'; diff --git a/src/utilities/assertions.ts b/src/common/utilities/assertions.ts similarity index 100% rename from src/utilities/assertions.ts rename to src/common/utilities/assertions.ts diff --git a/src/encoder.ts b/src/common/utilities/encoder.ts similarity index 100% rename from src/encoder.ts rename to src/common/utilities/encoder.ts diff --git a/src/utilities/path-pattern.ts b/src/common/utilities/path-pattern.ts similarity index 100% rename from src/utilities/path-pattern.ts rename to src/common/utilities/path-pattern.ts diff --git a/src/utilities/path.ts b/src/common/utilities/path.ts similarity index 100% rename from src/utilities/path.ts rename to src/common/utilities/path.ts diff --git a/src/utils.ts b/src/common/utilities/utils.ts similarity index 100% rename from src/utils.ts rename to src/common/utilities/utils.ts diff --git a/src/setup.ts b/src/setup.ts deleted file mode 100644 index 6a9db702d..000000000 --- a/src/setup.ts +++ /dev/null @@ -1,67 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 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. - -/** @hidden */ -import { firebaseConfig } from './config'; -import { warn } from './logger'; - -// Set up for config and vars -export function setup() { - // TEMPORARY WORKAROUND (BUG 63586213): - // Until the Cloud Functions builder can publish FIREBASE_CONFIG, automatically provide it on import based on what - // we can deduce. - if (!process.env.FIREBASE_CONFIG) { - const cfg = firebaseConfig(); - if (cfg) { - process.env.FIREBASE_CONFIG = JSON.stringify(cfg); - } - } - - // WORKAROUND (BUG 134416569): GCLOUD_PROJECT missing in Node 10 - if (!process.env.GCLOUD_PROJECT && process.env.FIREBASE_CONFIG) { - process.env.GCLOUD_PROJECT = JSON.parse( - process.env.FIREBASE_CONFIG - ).projectId; - } - - // If FIREBASE_CONFIG is still not found, try using GCLOUD_PROJECT to estimate - if (!process.env.FIREBASE_CONFIG) { - if (process.env.GCLOUD_PROJECT) { - warn( - 'Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail' - ); - process.env.FIREBASE_CONFIG = JSON.stringify({ - databaseURL: - process.env.DATABASE_URL || - `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`, - storageBucket: - process.env.STORAGE_BUCKET_URL || - `${process.env.GCLOUD_PROJECT}.appspot.com`, - projectId: process.env.GCLOUD_PROJECT, - }); - } else { - warn( - 'Warning, FIREBASE_CONFIG and GCLOUD_PROJECT environment variables are missing. Initializing firebase-admin will fail' - ); - } - } -} diff --git a/src/cloud-functions.ts b/src/v1/cloud-functions.ts similarity index 84% rename from src/cloud-functions.ts rename to src/v1/cloud-functions.ts index 07c117d4a..dd97804ab 100644 --- a/src/cloud-functions.ts +++ b/src/v1/cloud-functions.ts @@ -21,22 +21,11 @@ // SOFTWARE. import { Request, Response } from 'express'; -import { - DEFAULT_FAILURE_POLICY, - DeploymentOptions, - FailurePolicy, - Schedule, -} from './function-configuration'; -import { warn } from './logger'; +import { warn } from '../logger'; +import { DeploymentOptions } from './function-configuration'; export { Request, Response }; -import { - convertIfPresent, - copyIfPresent, - Duration, - durationFromSeconds, - serviceAccountFromShorthand, -} from './common/encoding'; -import { ManifestEndpoint, ManifestRequiredAPI } from './runtime/manifest'; +import { convertIfPresent, copyIfPresent } from '../common/encoding'; +import { ManifestEndpoint, ManifestRequiredAPI } from '../runtime/manifest'; /** @hidden */ const WILDCARD_REGEX = new RegExp('{[^/{}]*}', 'g'); @@ -270,36 +259,6 @@ export interface Resource { labels?: { [tag: string]: string }; } -/** - * TriggerAnnotion is used internally by the firebase CLI to understand what - * type of Cloud Function to deploy. - */ -interface TriggerAnnotation { - availableMemoryMb?: number; - blockingTrigger?: { - eventType: string; - options?: Record; - }; - eventTrigger?: { - eventType: string; - resource: string; - service: string; - }; - failurePolicy?: FailurePolicy; - httpsTrigger?: { - invoker?: string[]; - }; - labels?: { [key: string]: string }; - regions?: string[]; - schedule?: Schedule; - timeout?: Duration; - vpcConnector?: string; - vpcConnectorEgressSettings?: string; - serviceAccountEmail?: string; - ingressSettings?: string; - secrets?: string[]; -} - /** * A Runnable has a `run` method which directly invokes the user-defined * function - useful for unit testing. @@ -320,9 +279,6 @@ export interface Runnable { export interface HttpsFunction { (req: Request, resp: Response): void | Promise; - /** @alpha */ - __trigger: TriggerAnnotation; - /** @alpha */ __endpoint: ManifestEndpoint; @@ -336,9 +292,6 @@ export interface HttpsFunction { export interface BlockingFunction { (req: Request, resp: Response): void | Promise; - /** @alpha */ - __trigger: TriggerAnnotation; - /** @alpha */ __endpoint: ManifestEndpoint; @@ -356,9 +309,6 @@ export interface BlockingFunction { export interface CloudFunction extends Runnable { (input: any, context?: any): PromiseLike | any; - /** @alpha */ - __trigger: TriggerAnnotation; - /** @alpha */ __endpoint: ManifestEndpoint; @@ -452,27 +402,6 @@ export function makeCloudFunction({ return Promise.resolve(promise); }; - Object.defineProperty(cloudFunction, '__trigger', { - get: () => { - if (triggerResource() == null) { - return {}; - } - - const trigger: any = { - ...optionsToTrigger(options), - eventTrigger: { - resource: triggerResource(), - eventType: legacyEventType || provider + '.' + eventType, - service, - }, - }; - if (!!labels && Object.keys(labels).length) { - trigger.labels = { ...trigger.labels, ...labels }; - } - return trigger; - }, - }); - Object.defineProperty(cloudFunction, '__endpoint', { get: () => { if (triggerResource() == null) { @@ -570,67 +499,6 @@ function _detectAuthType(event: Event) { return 'UNAUTHENTICATED'; } -/** @hidden */ -export function optionsToTrigger(options: DeploymentOptions) { - const trigger: any = {}; - copyIfPresent( - trigger, - options, - 'regions', - 'schedule', - 'minInstances', - 'maxInstances', - 'ingressSettings', - 'vpcConnectorEgressSettings', - 'vpcConnector', - 'labels', - 'secrets' - ); - convertIfPresent( - trigger, - options, - 'failurePolicy', - 'failurePolicy', - (policy) => { - if (policy === false) { - return undefined; - } else if (policy === true) { - return DEFAULT_FAILURE_POLICY; - } else { - return policy; - } - } - ); - convertIfPresent( - trigger, - options, - 'timeout', - 'timeoutSeconds', - durationFromSeconds - ); - convertIfPresent(trigger, options, 'availableMemoryMb', 'memory', (mem) => { - const memoryLookup = { - '128MB': 128, - '256MB': 256, - '512MB': 512, - '1GB': 1024, - '2GB': 2048, - '4GB': 4096, - '8GB': 8192, - }; - return memoryLookup[mem]; - }); - convertIfPresent( - trigger, - options, - 'serviceAccountEmail', - 'serviceAccount', - serviceAccountFromShorthand - ); - - return trigger; -} - export function optionsToEndpoint( options: DeploymentOptions ): ManifestEndpoint { diff --git a/src/config.ts b/src/v1/config.ts similarity index 53% rename from src/config.ts rename to src/v1/config.ts index 01ca3a4cc..9ff7c1d24 100644 --- a/src/config.ts +++ b/src/v1/config.ts @@ -23,21 +23,16 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as firebase from 'firebase-admin'; +export { firebaseConfig } from '../common/config'; -export function config(): config.Config { - // K_CONFIGURATION is only set in GCFv2 - if (process.env.K_CONFIGURATION) { - throw new Error( - 'functions.config() is no longer available in Cloud Functions for ' + - 'Firebase v2. Please see the latest documentation for information ' + - 'on how to transition to using environment variables' - ); - } - if (typeof config.singleton === 'undefined') { - init(); - } - return config.singleton; +let singleton: Record; + +/** + * @hidden + * @internal + */ +export function resetCache(): void { + singleton = undefined; } /** @@ -46,76 +41,26 @@ export function config(): config.Config { * Firebase CLI as described in * [Environment Configuration](/docs/functions/config-env). */ -export namespace config { - /** - * The Functions configuration interface. - * - * Access via `functions.config()`. - */ - export interface Config { - [key: string]: any; - } - - /** @hidden */ - export let singleton: config.Config; -} - -/** @hidden */ -export let firebaseConfigCache: firebase.AppOptions | null = null; - -/** @hidden */ -export function firebaseConfig(): firebase.AppOptions | null { - if (firebaseConfigCache) { - return firebaseConfigCache; - } - - let env = process.env.FIREBASE_CONFIG; - if (env) { - // Firebase Tools will always use a JSON blob in prod, but docs - // explicitly state that the user can set the env to a file: - // https://firebase.google.com/docs/admin/setup#initialize-without-parameters - if (!env.startsWith('{')) { - env = fs.readFileSync(path.join(process.env.PWD, env)).toString('utf8'); - } - - firebaseConfigCache = JSON.parse(env); - return firebaseConfigCache; - } - - // Could have Runtime Config with Firebase in it as an ENV value. - try { - const config = JSON.parse(process.env.CLOUD_RUNTIME_CONFIG); - if (config.firebase) { - firebaseConfigCache = config.firebase; - return firebaseConfigCache; - } - } catch (e) { - // Do nothing +export function config(): Record { + // K_CONFIGURATION is only set in GCFv2 + if (process.env.K_CONFIGURATION) { + throw new Error( + 'functions.config() is no longer available in Cloud Functions for ' + + 'Firebase v2. Please see the latest documentation for information ' + + 'on how to transition to using environment variables' + ); } - - // Could have Runtime Config with Firebase in it as an ENV location or default. - try { - const configPath = - process.env.CLOUD_RUNTIME_CONFIG || - path.join(process.cwd(), '.runtimeconfig.json'); - const contents = fs.readFileSync(configPath); - const config = JSON.parse(contents.toString('utf8')); - if (config.firebase) { - firebaseConfigCache = config.firebase; - return firebaseConfigCache; - } - } catch (e) { - // Do nothing + if (typeof singleton === 'undefined') { + init(); } - - return null; + return singleton; } function init() { try { const parsed = JSON.parse(process.env.CLOUD_RUNTIME_CONFIG); delete parsed.firebase; - config.singleton = parsed; + singleton = parsed; return; } catch (e) { // Do nothing @@ -128,11 +73,11 @@ function init() { const contents = fs.readFileSync(configPath); const parsed = JSON.parse(contents.toString('utf8')); delete parsed.firebase; - config.singleton = parsed; + singleton = parsed; return; } catch (e) { // Do nothing } - config.singleton = {}; + singleton = {}; } diff --git a/src/function-builder.ts b/src/v1/function-builder.ts similarity index 100% rename from src/function-builder.ts rename to src/v1/function-builder.ts diff --git a/src/function-configuration.ts b/src/v1/function-configuration.ts similarity index 98% rename from src/function-configuration.ts rename to src/v1/function-configuration.ts index 2568d67a9..be0642cf3 100644 --- a/src/function-configuration.ts +++ b/src/v1/function-configuration.ts @@ -92,10 +92,6 @@ export interface FailurePolicy { retry: {}; } -export const DEFAULT_FAILURE_POLICY: FailurePolicy = { - retry: {}, -}; - export const MAX_NUMBER_USER_LABELS = 58; export interface RuntimeOptions { diff --git a/src/handler-builder.ts b/src/v1/handler-builder.ts similarity index 99% rename from src/handler-builder.ts rename to src/v1/handler-builder.ts index dcce26bcc..454ad016f 100644 --- a/src/handler-builder.ts +++ b/src/v1/handler-builder.ts @@ -69,7 +69,6 @@ export class HandlerBuilder { handler: (req: express.Request, resp: express.Response) => void ): HttpsFunction => { const func = https._onRequestWithOptions(handler, {}); - func.__trigger = {}; func.__endpoint = undefined; func.__requiredAPIs = undefined; return func; @@ -81,7 +80,6 @@ export class HandlerBuilder { ) => any | Promise ): HttpsFunction => { const func = https._onCallWithOptions(handler, {}); - func.__trigger = {}; func.__endpoint = undefined; func.__requiredAPIs = undefined; return func; @@ -110,7 +108,6 @@ export class HandlerBuilder { ): HttpsFunction => { const builder = new tasks.TaskQueueBuilder(); const func = builder.onDispatch(handler); - func.__trigger = {}; func.__endpoint = undefined; func.__requiredAPIs = undefined; return func; diff --git a/src/index.ts b/src/v1/index.ts similarity index 93% rename from src/index.ts rename to src/v1/index.ts index e7b23b834..3255dffa0 100644 --- a/src/index.ts +++ b/src/v1/index.ts @@ -21,6 +21,7 @@ // SOFTWARE. // Providers: +import * as logger from '../logger'; import * as analytics from './providers/analytics'; import * as auth from './providers/auth'; import * as database from './providers/database'; @@ -32,10 +33,8 @@ import * as storage from './providers/storage'; import * as tasks from './providers/tasks'; import * as testLab from './providers/testLab'; -import { setApp as setEmulatedAdminApp } from './common/app'; +import { setApp as setEmulatedAdminApp } from '../common/app'; import { handler } from './handler-builder'; -import * as logger from './logger'; -import { setup } from './setup'; export { analytics, @@ -59,5 +58,3 @@ export * from './cloud-functions'; export * from './config'; export * from './function-builder'; export * from './function-configuration'; - -setup(); diff --git a/src/providers/analytics.ts b/src/v1/providers/analytics.ts similarity index 100% rename from src/providers/analytics.ts rename to src/v1/providers/analytics.ts diff --git a/src/providers/auth.ts b/src/v1/providers/auth.ts similarity index 95% rename from src/providers/auth.ts rename to src/v1/providers/auth.ts index f845424ea..190441c55 100644 --- a/src/providers/auth.ts +++ b/src/v1/providers/auth.ts @@ -20,15 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { - BlockingFunction, - CloudFunction, - Event, - EventContext, - makeCloudFunction, - optionsToEndpoint, - optionsToTrigger, -} from '../cloud-functions'; import { AuthBlockingEventType, AuthEventContext, @@ -41,7 +32,15 @@ import { userRecordConstructor, UserRecordMetadata, wrapHandler, -} from '../common/providers/identity'; +} from '../../common/providers/identity'; +import { + BlockingFunction, + CloudFunction, + Event, + EventContext, + makeCloudFunction, + optionsToEndpoint, +} from '../cloud-functions'; import { DeploymentOptions } from '../function-configuration'; // TODO: yank in next breaking change release @@ -208,19 +207,6 @@ export class UserBuilder { const legacyEventType = `providers/cloud.auth/eventTypes/user.${eventType}`; - func.__trigger = { - labels: {}, - ...optionsToTrigger(this.options), - blockingTrigger: { - eventType: legacyEventType, - options: { - accessToken, - idToken, - refreshToken, - }, - }, - }; - func.__endpoint = { platform: 'gcfv1', labels: {}, diff --git a/src/providers/database.ts b/src/v1/providers/database.ts similarity index 97% rename from src/providers/database.ts rename to src/v1/providers/database.ts index 8dba83ffc..386201d39 100644 --- a/src/providers/database.ts +++ b/src/v1/providers/database.ts @@ -20,6 +20,11 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +import { getApp } from '../../common/app'; +import { firebaseConfig } from '../../common/config'; +import { DataSnapshot } from '../../common/providers/database'; +import { normalizePath } from '../../common/utilities/path'; +import { applyChange } from '../../common/utilities/utils'; import { Change, CloudFunction, @@ -27,12 +32,7 @@ import { EventContext, makeCloudFunction, } from '../cloud-functions'; -import { getApp } from '../common/app'; -import { DataSnapshot } from '../common/providers/database'; -import { firebaseConfig } from '../config'; import { DeploymentOptions } from '../function-configuration'; -import { normalizePath } from '../utilities/path'; -import { applyChange } from '../utils'; export { DataSnapshot }; diff --git a/src/providers/firestore.ts b/src/v1/providers/firestore.ts similarity index 98% rename from src/providers/firestore.ts rename to src/v1/providers/firestore.ts index e159d62bf..de5e64a5b 100644 --- a/src/providers/firestore.ts +++ b/src/v1/providers/firestore.ts @@ -23,6 +23,9 @@ import * as firestore from 'firebase-admin/firestore'; import { posix } from 'path'; +import { getApp } from '../../common/app'; +import { dateToTimestampProto } from '../../common/utilities/encoder'; +import * as logger from '../../logger'; import { Change, CloudFunction, @@ -30,10 +33,7 @@ import { EventContext, makeCloudFunction, } from '../cloud-functions'; -import { getApp } from '../common/app'; -import { dateToTimestampProto } from '../encoder'; import { DeploymentOptions } from '../function-configuration'; -import * as logger from '../logger'; /** @hidden */ export const provider = 'google.firestore'; diff --git a/src/providers/https.ts b/src/v1/providers/https.ts similarity index 84% rename from src/providers/https.ts rename to src/v1/providers/https.ts index b50c9764b..a6af2a06d 100644 --- a/src/providers/https.ts +++ b/src/v1/providers/https.ts @@ -22,20 +22,15 @@ import * as express from 'express'; -import { - HttpsFunction, - optionsToEndpoint, - optionsToTrigger, - Runnable, -} from '../cloud-functions'; -import { convertIfPresent, convertInvoker } from '../common/encoding'; +import { convertIfPresent, convertInvoker } from '../../common/encoding'; import { CallableContext, FunctionsErrorCode, HttpsError, onCallHandler, Request, -} from '../common/providers/https'; +} from '../../common/providers/https'; +import { HttpsFunction, optionsToEndpoint, Runnable } from '../cloud-functions'; import { DeploymentOptions } from '../function-configuration'; export { Request, CallableContext, FunctionsErrorCode, HttpsError }; @@ -66,21 +61,10 @@ export function _onRequestWithOptions( handler: (req: Request, resp: express.Response) => void | Promise, options: DeploymentOptions ): HttpsFunction { - // lets us add __trigger without altering handler: + // lets us add __endpoint without altering handler: const cloudFunction: any = (req: Request, res: express.Response) => { return handler(req, res); }; - cloudFunction.__trigger = { - ...optionsToTrigger(options), - httpsTrigger: {}, - }; - convertIfPresent( - cloudFunction.__trigger.httpsTrigger, - options, - 'invoker', - 'invoker', - convertInvoker - ); // TODO parse the options cloudFunction.__endpoint = { @@ -116,13 +100,6 @@ export function _onCallWithOptions( fixedLen ); - func.__trigger = { - labels: {}, - ...optionsToTrigger(options), - httpsTrigger: {}, - }; - func.__trigger.labels['deployment-callable'] = 'true'; - func.__endpoint = { platform: 'gcfv1', labels: {}, diff --git a/src/providers/pubsub.ts b/src/v1/providers/pubsub.ts similarity index 100% rename from src/providers/pubsub.ts rename to src/v1/providers/pubsub.ts diff --git a/src/providers/remoteConfig.ts b/src/v1/providers/remoteConfig.ts similarity index 100% rename from src/providers/remoteConfig.ts rename to src/v1/providers/remoteConfig.ts diff --git a/src/providers/storage.ts b/src/v1/providers/storage.ts similarity index 99% rename from src/providers/storage.ts rename to src/v1/providers/storage.ts index 33b2a64eb..8aaf8a3f8 100644 --- a/src/providers/storage.ts +++ b/src/v1/providers/storage.ts @@ -20,12 +20,12 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +import { firebaseConfig } from '../../common/config'; import { CloudFunction, EventContext, makeCloudFunction, } from '../cloud-functions'; -import { firebaseConfig } from '../config'; import { DeploymentOptions } from '../function-configuration'; /** @hidden */ diff --git a/src/providers/tasks.ts b/src/v1/providers/tasks.ts similarity index 86% rename from src/providers/tasks.ts rename to src/v1/providers/tasks.ts index f06e7b92e..284c91262 100644 --- a/src/providers/tasks.ts +++ b/src/v1/providers/tasks.ts @@ -22,21 +22,21 @@ import * as express from 'express'; -import { optionsToEndpoint, optionsToTrigger } from '../cloud-functions'; import { convertIfPresent, convertInvoker, copyIfPresent, -} from '../common/encoding'; -import { Request } from '../common/providers/https'; +} from '../../common/encoding'; +import { Request } from '../../common/providers/https'; import { onDispatchHandler, RateLimits, RetryConfig, TaskContext, -} from '../common/providers/tasks'; +} from '../../common/providers/tasks'; +import { ManifestEndpoint, ManifestRequiredAPI } from '../../runtime/manifest'; +import { optionsToEndpoint } from '../cloud-functions'; import { DeploymentOptions } from '../function-configuration'; -import { ManifestEndpoint, ManifestRequiredAPI } from '../runtime/manifest'; export { RetryConfig, RateLimits, TaskContext }; @@ -64,9 +64,6 @@ export interface TaskQueueOptions { export interface TaskQueueFunction { (req: Request, res: express.Response): Promise; - /** @alpha */ - __trigger: unknown; - /** @alpha */ __endpoint: ManifestEndpoint; @@ -109,20 +106,6 @@ export class TaskQueueBuilder { handler(data, context); const func: any = onDispatchHandler(fixedLen); - func.__trigger = { - ...optionsToTrigger(this.depOpts || {}), - taskQueueTrigger: {}, - }; - copyIfPresent(func.__trigger.taskQueueTrigger, this.tqOpts, 'retryConfig'); - copyIfPresent(func.__trigger.taskQueueTrigger, this.tqOpts, 'rateLimits'); - convertIfPresent( - func.__trigger.taskQueueTrigger, - this.tqOpts, - 'invoker', - 'invoker', - convertInvoker - ); - func.__endpoint = { platform: 'gcfv1', ...optionsToEndpoint(this.depOpts), diff --git a/src/providers/testLab.ts b/src/v1/providers/testLab.ts similarity index 100% rename from src/providers/testLab.ts rename to src/v1/providers/testLab.ts diff --git a/src/v2/core.ts b/src/v2/core.ts index 5e71d2458..023a488e8 100644 --- a/src/v2/core.ts +++ b/src/v2/core.ts @@ -27,37 +27,6 @@ import { ManifestEndpoint } from '../runtime/manifest'; -/** @internal */ -export interface TriggerAnnotation { - platform?: string; - concurrency?: number; - minInstances?: number; - maxInstances?: number; - availableMemoryMb?: number; - eventTrigger?: { - eventType: string; - resource: string; - service: string; - }; - failurePolicy?: { retry: boolean }; - httpsTrigger?: { - invoker?: string[]; - }; - labels?: { [key: string]: string }; - regions?: string[]; - timeout?: string; - vpcConnector?: string; - vpcConnectorEgressSettings?: string; - serviceAccountEmail?: string; - ingressSettings?: string; - secrets?: string[]; - blockingTrigger?: { - eventType: string; - options?: Record; - }; - // TODO: schedule -} - /** * A CloudEventBase is the base of a cross-platform format for encoding a serverless event. * More information can be found in https://github.com/cloudevents/spec @@ -96,8 +65,6 @@ export interface CloudEvent { export interface CloudFunction> { (raw: CloudEvent): any | Promise; - /** @alpha */ - __trigger?: unknown; /** @alpha */ __endpoint: ManifestEndpoint; diff --git a/src/v2/options.ts b/src/v2/options.ts index 06bb9aebd..e55ed8e40 100644 --- a/src/v2/options.ts +++ b/src/v2/options.ts @@ -25,15 +25,9 @@ * @packageDocumentation */ -import { - convertIfPresent, - copyIfPresent, - durationFromSeconds, - serviceAccountFromShorthand, -} from '../common/encoding'; +import { convertIfPresent, copyIfPresent } from '../common/encoding'; import * as logger from '../logger'; import { ManifestEndpoint } from '../runtime/manifest'; -import { TriggerAnnotation } from './core'; import { declaredParams } from './params'; import { ParamSpec } from './params/types'; import { HttpsOptions } from './providers/https'; @@ -230,68 +224,6 @@ export interface EventHandlerOptions retry?: boolean; } -/** - * Apply GlobalOptions to trigger definitions. - * @internal - */ -export function optionsToTriggerAnnotations( - opts: GlobalOptions | EventHandlerOptions | HttpsOptions -): TriggerAnnotation { - const annotation: TriggerAnnotation = {}; - copyIfPresent( - annotation, - opts, - 'concurrency', - 'minInstances', - 'maxInstances', - 'ingressSettings', - 'labels', - 'vpcConnector', - 'vpcConnectorEgressSettings', - 'secrets' - ); - convertIfPresent( - annotation, - opts, - 'availableMemoryMb', - 'memory', - (mem: MemoryOption) => { - return MemoryOptionToMB[mem]; - } - ); - convertIfPresent(annotation, opts, 'regions', 'region', (region) => { - if (typeof region === 'string') { - return [region]; - } - return region; - }); - convertIfPresent( - annotation, - opts, - 'serviceAccountEmail', - 'serviceAccount', - serviceAccountFromShorthand - ); - convertIfPresent( - annotation, - opts, - 'timeout', - 'timeoutSeconds', - durationFromSeconds - ); - convertIfPresent( - annotation, - (opts as any) as EventHandlerOptions, - 'failurePolicy', - 'retry', - (retry: boolean) => { - return retry ? { retry: true } : null; - } - ); - - return annotation; -} - /** * Apply GlobalOptions to endpoint manifest. * @internal diff --git a/src/v2/providers/database.ts b/src/v2/providers/database.ts index 372a949e8..55c1f7838 100644 --- a/src/v2/providers/database.ts +++ b/src/v2/providers/database.ts @@ -20,13 +20,13 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { Change } from '../../cloud-functions'; import { getApp } from '../../common/app'; import { DataSnapshot } from '../../common/providers/database'; +import { normalizePath } from '../../common/utilities/path'; +import { PathPattern } from '../../common/utilities/path-pattern'; +import { applyChange } from '../../common/utilities/utils'; import { ManifestEndpoint } from '../../runtime/manifest'; -import { normalizePath } from '../../utilities/path'; -import { PathPattern } from '../../utilities/path-pattern'; -import { applyChange } from '../../utils'; +import { Change } from '../../v1/cloud-functions'; import { CloudEvent, CloudFunction } from '../core'; import * as options from '../options'; diff --git a/src/v2/providers/https.ts b/src/v2/providers/https.ts index 3d9510e1c..b6fae6348 100644 --- a/src/v2/providers/https.ts +++ b/src/v2/providers/https.ts @@ -172,8 +172,6 @@ export type HttpsFunction = (( /** An Express response object, for this function to respond to callers. */ res: express.Response ) => void | Promise) & { - /** @alpha */ - __trigger?: unknown; /** @alpha */ __endpoint: ManifestEndpoint; }; @@ -245,39 +243,6 @@ export function onRequest( }; } - Object.defineProperty(handler, '__trigger', { - get: () => { - const baseOpts = options.optionsToTriggerAnnotations( - options.getGlobalOptions() - ); - // global options calls region a scalar and https allows it to be an array, - // but optionsToTriggerAnnotations handles both cases. - const specificOpts = options.optionsToTriggerAnnotations( - opts as options.GlobalOptions - ); - const trigger: any = { - platform: 'gcfv2', - ...baseOpts, - ...specificOpts, - labels: { - ...baseOpts?.labels, - ...specificOpts?.labels, - }, - httpsTrigger: { - allowInsecure: false, - }, - }; - convertIfPresent( - trigger.httpsTrigger, - opts, - 'invoker', - 'invoker', - convertInvoker - ); - return trigger; - }, - }); - const baseOpts = options.optionsToEndpoint(options.getGlobalOptions()); // global options calls region a scalar and https allows it to be an array, // but optionsToTriggerAnnotations handles both cases. @@ -352,30 +317,6 @@ export function onCall>( fixedLen ); - Object.defineProperty(func, '__trigger', { - get: () => { - const baseOpts = options.optionsToTriggerAnnotations( - options.getGlobalOptions() - ); - // global options calls region a scalar and https allows it to be an array, - // but optionsToTriggerAnnotations handles both cases. - const specificOpts = options.optionsToTriggerAnnotations(opts); - return { - platform: 'gcfv2', - ...baseOpts, - ...specificOpts, - labels: { - ...baseOpts?.labels, - ...specificOpts?.labels, - 'deployment-callable': 'true', - }, - httpsTrigger: { - allowInsecure: false, - }, - }; - }, - }); - const baseOpts = options.optionsToEndpoint(options.getGlobalOptions()); // global options calls region a scalar and https allows it to be an array, // but optionsToEndpoint handles both cases. diff --git a/src/v2/providers/identity.ts b/src/v2/providers/identity.ts index b68136d8e..7e255b779 100644 --- a/src/v2/providers/identity.ts +++ b/src/v2/providers/identity.ts @@ -25,7 +25,6 @@ * @packageDocumentation */ -import { BlockingFunction } from '../../cloud-functions'; import { AuthBlockingEvent, AuthBlockingEventType, @@ -34,6 +33,7 @@ import { HttpsError, wrapHandler, } from '../../common/providers/identity'; +import { BlockingFunction } from '../../v1/cloud-functions'; import * as options from '../options'; export { HttpsError }; diff --git a/src/v2/providers/pubsub.ts b/src/v2/providers/pubsub.ts index 380ed6946..7b7993bc5 100644 --- a/src/v2/providers/pubsub.ts +++ b/src/v2/providers/pubsub.ts @@ -303,29 +303,6 @@ export function onMessagePublished( func.run = handler; - Object.defineProperty(func, '__trigger', { - get: () => { - const baseOpts = options.optionsToTriggerAnnotations( - options.getGlobalOptions() - ); - const specificOpts = options.optionsToTriggerAnnotations(opts); - - return { - platform: 'gcfv2', - ...baseOpts, - ...specificOpts, - labels: { - ...baseOpts?.labels, - ...specificOpts?.labels, - }, - eventTrigger: { - eventType: 'google.cloud.pubsub.topic.v1.messagePublished', - resource: `projects/${process.env.GCLOUD_PROJECT}/topics/${topic}`, - }, - }; - }, - }); - const baseOpts = options.optionsToEndpoint(options.getGlobalOptions()); const specificOpts = options.optionsToEndpoint(opts); diff --git a/src/v2/providers/storage.ts b/src/v2/providers/storage.ts index 33281abd1..0087119e0 100644 --- a/src/v2/providers/storage.ts +++ b/src/v2/providers/storage.ts @@ -25,8 +25,8 @@ * @packageDocumentation */ +import { firebaseConfig } from '../../common/config'; import { copyIfPresent } from '../../common/encoding'; -import { firebaseConfig } from '../../config'; import { ManifestEndpoint } from '../../runtime/manifest'; import { CloudEvent, CloudFunction } from '../core'; import * as options from '../options'; @@ -569,29 +569,6 @@ export function onOperation( func.run = handler; - Object.defineProperty(func, '__trigger', { - get: () => { - const baseOpts = options.optionsToTriggerAnnotations( - options.getGlobalOptions() - ); - const specificOpts = options.optionsToTriggerAnnotations(opts); - - return { - platform: 'gcfv2', - ...baseOpts, - ...specificOpts, - labels: { - ...baseOpts?.labels, - ...specificOpts?.labels, - }, - eventTrigger: { - eventType, - resource: bucket, // TODO(colerogers): replace with 'bucket,' eventually - }, - }; - }, - }); - // TypeScript doesn't recognize defineProperty as adding a property and complains // that __endpoint doesn't exist. We can either cast to any and lose all type safety // or we can just assign a meaningless value before calling defineProperty. diff --git a/src/v2/providers/tasks.ts b/src/v2/providers/tasks.ts index df3b9b8c2..eae3e53dd 100644 --- a/src/v2/providers/tasks.ts +++ b/src/v2/providers/tasks.ts @@ -206,38 +206,6 @@ export function onTaskDispatched( const fixedLen = (req: Request) => handler(req); const func: any = onDispatchHandler(fixedLen); - Object.defineProperty(func, '__trigger', { - get: () => { - const baseOpts = options.optionsToTriggerAnnotations( - options.getGlobalOptions() - ); - // global options calls region a scalar and https allows it to be an array, - // but optionsToTriggerAnnotations handles both cases. - const specificOpts = options.optionsToTriggerAnnotations( - opts as options.GlobalOptions - ); - const taskQueueTrigger: Record = {}; - copyIfPresent(taskQueueTrigger, opts, 'retryConfig', 'rateLimits'); - convertIfPresent( - taskQueueTrigger, - opts, - 'invoker', - 'invoker', - convertInvoker - ); - return { - platform: 'gcfv2', - ...baseOpts, - ...specificOpts, - labels: { - ...baseOpts?.labels, - ...specificOpts?.labels, - }, - taskQueueTrigger, - }; - }, - }); - const baseOpts = options.optionsToEndpoint(options.getGlobalOptions()); // global options calls region a scalar and https allows it to be an array, // but optionsToManifestEndpoint handles both cases. diff --git a/tsconfig.release.json b/tsconfig.release.json index 93bbefe3a..5d48aa842 100644 --- a/tsconfig.release.json +++ b/tsconfig.release.json @@ -12,7 +12,7 @@ }, "files": [ "./src/types/global.d.ts", - "./src/index.ts", + "./src/v1/index.ts", "./src/logger/index.ts", "./src/logger/compat.ts", "./src/v2/index.ts", From 151eda98d383ec4f6c5578b5ac034a74c105140c Mon Sep 17 00:00:00 2001 From: Jasper Concepcion Date: Tue, 28 Jun 2022 12:10:21 +0800 Subject: [PATCH 08/63] add firebase@11.0.0 to peerDependencies (#1152) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0001abce2..cccd8c0e8 100644 --- a/package.json +++ b/package.json @@ -212,7 +212,7 @@ "yargs": "^15.3.1" }, "peerDependencies": { - "firebase-admin": "^10.0.0" + "firebase-admin": "^10.0.0 || ^11.0.0" }, "engines": { "node": ">=14.10.0" From 35a16324c59b54d292a1d6d14986d5abc21f5859 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 30 Jun 2022 11:51:04 -0700 Subject: [PATCH 09/63] Fix bad import path. --- src/v1/cloud-functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v1/cloud-functions.ts b/src/v1/cloud-functions.ts index 9f0c44e06..9f404eb63 100644 --- a/src/v1/cloud-functions.ts +++ b/src/v1/cloud-functions.ts @@ -27,7 +27,7 @@ export { Request, Response }; import { convertIfPresent, copyIfPresent } from '../common/encoding'; import { ManifestEndpoint, ManifestRequiredAPI } from '../runtime/manifest'; -export { Change } from './common/change'; +export { Change } from '../common/change'; /** @hidden */ const WILDCARD_REGEX = new RegExp('{[^/{}]*}', 'g'); From 94fd1c6101ede62d93018af3aeced9573f89b29b Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Thu, 30 Jun 2022 11:57:52 -0700 Subject: [PATCH 10/63] Unrevert revert DataSnapshot changes. --- spec/v1/providers/database.spec.ts | 146 +++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 9 deletions(-) diff --git a/spec/v1/providers/database.spec.ts b/spec/v1/providers/database.spec.ts index 49b0c28b4..3891ae383 100644 --- a/spec/v1/providers/database.spec.ts +++ b/spec/v1/providers/database.spec.ts @@ -569,10 +569,6 @@ describe('Database Functions', () => { expect(subject.val()).to.equal(0); populate({ myKey: 0 }); expect(subject.val()).to.deep.equal({ myKey: 0 }); - - // Null values are still reported as null. - populate({ myKey: null }); - expect(subject.val()).to.deep.equal({ myKey: null }); }); // Regression test: .val() was returning array of nulls when there's a property called length (BUG#37683995) @@ -580,6 +576,45 @@ describe('Database Functions', () => { populate({ length: 3, foo: 'bar' }); expect(subject.val()).to.deep.equal({ length: 3, foo: 'bar' }); }); + + it('should deal with null-values appropriately', () => { + populate(null); + expect(subject.val()).to.be.null; + + populate({ myKey: null }); + expect(subject.val()).to.be.null; + }); + + it('should deal with empty object values appropriately', () => { + populate({}); + expect(subject.val()).to.be.null; + + populate({ myKey: {} }); + expect(subject.val()).to.be.null; + + populate({ myKey: { child: null } }); + expect(subject.val()).to.be.null; + }); + + it('should deal with empty array values appropriately', () => { + populate([]); + expect(subject.val()).to.be.null; + + populate({ myKey: [] }); + expect(subject.val()).to.be.null; + + populate({ myKey: [null] }); + expect(subject.val()).to.be.null; + + populate({ myKey: [{}] }); + expect(subject.val()).to.be.null; + + populate({ myKey: [{ myKey: null }] }); + expect(subject.val()).to.be.null; + + populate({ myKey: [{ myKey: {} }] }); + expect(subject.val()).to.be.null; + }); }); describe('#child(): DataSnapshot', () => { @@ -606,14 +641,37 @@ describe('Database Functions', () => { }); it('should be false for a non-existent value', () => { - populate({ a: { b: 'c' } }); + populate({ a: { b: 'c', nullChild: null } }); expect(subject.child('d').exists()).to.be.false; + expect(subject.child('nullChild').exists()).to.be.false; }); it('should be false for a value pathed beyond a leaf', () => { populate({ a: { b: 'c' } }); expect(subject.child('a/b/c').exists()).to.be.false; }); + + it('should be false for an empty object value', () => { + populate({ a: {} }); + expect(subject.child('a').exists()).to.be.false; + + populate({ a: { child: null } }); + expect(subject.child('a').exists()).to.be.false; + + populate({ a: { child: {} } }); + expect(subject.child('a').exists()).to.be.false; + }); + + it('should be false for an empty array value', () => { + populate({ a: [] }); + expect(subject.child('a').exists()).to.be.false; + + populate({ a: [null] }); + expect(subject.child('a').exists()).to.be.false; + + populate({ a: [{}] }); + expect(subject.child('a').exists()).to.be.false; + }); }); describe('#forEach(action: (a: DataSnapshot) => boolean): boolean', () => { @@ -642,6 +700,17 @@ describe('Database Functions', () => { expect(subject.forEach(counter)).to.equal(false); expect(count).to.eq(0); + + populate({ + a: 'foo', + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); + count = 0; + + expect(subject.forEach(counter)).to.equal(false); + expect(count).to.eq(1); }); it('should cancel further enumeration if callback returns true', () => { @@ -681,13 +750,51 @@ describe('Database Functions', () => { describe('#numChildren()', () => { it('should be key count for objects', () => { - populate({ a: 'b', c: 'd' }); + populate({ + a: 'b', + c: 'd', + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); expect(subject.numChildren()).to.eq(2); }); it('should be 0 for non-objects', () => { populate(23); expect(subject.numChildren()).to.eq(0); + + populate({ + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); + expect(subject.numChildren()).to.eq(0); + }); + }); + + describe('#hasChildren()', () => { + it('should true for objects', () => { + populate({ + a: 'b', + c: 'd', + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); + expect(subject.hasChildren()).to.be.true; + }); + + it('should be false for non-objects', () => { + populate(23); + expect(subject.hasChildren()).to.be.false; + + populate({ + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); + expect(subject.hasChildren()).to.be.false; }); }); @@ -699,7 +806,17 @@ describe('Database Functions', () => { }); it('should return false if a child is missing', () => { - populate({ a: 'b' }); + populate({ + a: 'b', + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); + expect(subject.hasChild('c')).to.be.false; + expect(subject.hasChild('a/b')).to.be.false; + expect(subject.hasChild('nullChild')).to.be.false; + expect(subject.hasChild('emptyObjectChild')).to.be.false; + expect(subject.hasChild('emptyArrayChild')).to.be.false; expect(subject.hasChild('c')).to.be.false; expect(subject.hasChild('a/b')).to.be.false; }); @@ -731,11 +848,22 @@ describe('Database Functions', () => { describe('#toJSON(): Object', () => { it('should return the current value', () => { - populate({ a: 'b' }); + populate({ + a: 'b', + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); expect(subject.toJSON()).to.deep.equal(subject.val()); }); + it('should be stringifyable', () => { - populate({ a: 'b' }); + populate({ + a: 'b', + nullChild: null, + emptyObjectChild: {}, + emptyArrayChild: [], + }); expect(JSON.stringify(subject)).to.deep.equal('{"a":"b"}'); }); }); From a215d8ec10c56e9dbc759c5f51cfac2d8160208b Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Wed, 13 Jul 2022 11:37:48 -0700 Subject: [PATCH 11/63] Update prettier. Run prettier (#1160) --- docgen/api-extractor.base.json | 728 ++++++++++++------------ integration_test/functions/src/index.ts | 21 +- package-lock.json | 41 +- package.json | 4 +- spec/common/providers/identity.spec.ts | 24 +- spec/v1/function-builder.spec.ts | 8 +- spec/v1/providers/auth.spec.ts | 5 +- spec/v1/providers/database.spec.ts | 7 +- spec/v1/providers/firestore.spec.ts | 3 +- spec/v2/providers/alerts/alerts.spec.ts | 5 +- src/common/utilities/path.ts | 4 +- src/logger/compat.ts | 2 +- src/v1/providers/database.ts | 3 +- src/v2/params/types.ts | 6 +- 14 files changed, 415 insertions(+), 446 deletions(-) diff --git a/docgen/api-extractor.base.json b/docgen/api-extractor.base.json index 2938a396f..869c825d6 100644 --- a/docgen/api-extractor.base.json +++ b/docgen/api-extractor.base.json @@ -1,364 +1,364 @@ -/** - * Config file for API Extractor. For more info, please visit: https://api-extractor.com - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - /** - * Optionally specifies another JSON config file that this file extends from. This provides a way for - * standard settings to be shared across multiple projects. - * - * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains - * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be - * resolved using NodeJS require(). - * - * SUPPORTED TOKENS: none - * DEFAULT VALUE: "" - */ - // "extends": "./shared/api-extractor-base.json" - // "extends": "my-package/include/api-extractor-base.json" - - /** - * Determines the "" token that can be used with other config file settings. The project folder - * typically contains the tsconfig.json and package.json config files, but the path is user-defined. - * - * The path is resolved relative to the folder of the config file that contains the setting. - * - * The default value for "projectFolder" is the token "", which means the folder is determined by traversing - * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder - * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error - * will be reported. - * - * SUPPORTED TOKENS: - * DEFAULT VALUE: "" - */ - "projectFolder": "..", - - /** - * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor - * analyzes the symbols exported by this module. - * - * The file extension must be ".d.ts" and not ".ts". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - */ - "mainEntryPointFilePath": "/lib/index.d.ts", - - /** - * A list of NPM package names whose exports should be treated as part of this package. - * - * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", - * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part - * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly - * imports library2. To avoid this, we can specify: - * - * "bundledPackages": [ "library2" ], - * - * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been - * local files for library1. - */ - "bundledPackages": [], - - /** - * Determines how the TypeScript compiler engine will be invoked by API Extractor. - */ - "compiler": { - /** - * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * Note: This setting will be ignored if "overrideTsconfig" is used. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/tsconfig.json" - */ - "tsconfigFilePath": "/tsconfig.release.json" - /** - * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. - * The object must conform to the TypeScript tsconfig schema: - * - * http://json.schemastore.org/tsconfig - * - * If omitted, then the tsconfig.json file will be read from the "projectFolder". - * - * DEFAULT VALUE: no overrideTsconfig section - */ - // "overrideTsconfig": { - // . . . - // } - /** - * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended - * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when - * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses - * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. - * - * DEFAULT VALUE: false - */ - // "skipLibCheck": true, - }, - - /** - * Configures how the API report file (*.api.md) will be generated. - */ - "apiReport": { - /** - * (REQUIRED) Whether to generate an API report. - */ - "enabled": true, - - /** - * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce - * a full file path. - * - * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". - * - * SUPPORTED TOKENS: , - * DEFAULT VALUE: ".api.md" - */ - // "reportFileName": ".api.md", - - /** - * Specifies the folder where the API report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, - * e.g. for an API review. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/etc/" - */ - "reportFolder": "/docgen/etc/", - - /** - * Specifies the folder where the temporary report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * After the temporary file is written to disk, it is compared with the file in the "reportFolder". - * If they are different, a production build will fail. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/" - */ - "reportTempFolder": "/docgen/temp/" - }, - - /** - * Configures how the doc model file (*.api.json) will be generated. - */ - "docModel": { - /** - * (REQUIRED) Whether to generate a doc model file. - */ - "enabled": true, - - /** - * The output path for the doc model file. The file extension should be ".api.json". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/.api.json" - */ - "apiJsonFilePath": "/docgen/.api.json" - }, - - /** - * Configures how the .d.ts rollup file will be generated. - */ - "dtsRollup": { - /** - * (REQUIRED) Whether to generate the .d.ts rollup file. - */ - "enabled": true - - /** - * Specifies the output path for a .d.ts rollup file to be generated without any trimming. - * This file will include all declarations that are exported by the main entry point. - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/dist/.d.ts" - */ - // "untrimmedFilePath": "/dist/.d.ts", - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. - * This file will include only declarations that are marked as "@public" or "@beta". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "betaTrimmedFilePath": "/dist/-beta.d.ts", - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. - * This file will include only declarations that are marked as "@public". - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "publicTrimmedFilePath": "/dist/-public.d.ts", - - /** - * When a declaration is trimmed, by default it will be replaced by a code comment such as - * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the - * declaration completely. - * - * DEFAULT VALUE: false - */ - // "omitTrimmingComments": true - }, - - /** - * Configures how the tsdoc-metadata.json file will be generated. - */ - "tsdocMetadata": { - /** - * Whether to generate the tsdoc-metadata.json file. - * - * DEFAULT VALUE: true - */ - // "enabled": true, - /** - * Specifies where the TSDoc metadata file should be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", - * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup - * falls back to "tsdoc-metadata.json" in the package folder. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" - }, - - /** - * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files - * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. - * To use the OS's default newline kind, specify "os". - * - * DEFAULT VALUE: "crlf" - */ - // "newlineKind": "crlf", - - /** - * Configures how API Extractor reports error and warning messages produced during analysis. - * - * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. - */ - "messages": { - /** - * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing - * the input .d.ts files. - * - * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "compilerMessageReporting": { - /** - * Configures the default routing for messages that don't match an explicit rule in this table. - */ - "default": { - /** - * Specifies whether the message should be written to the the tool's output log. Note that - * the "addToApiReportFile" property may supersede this option. - * - * Possible values: "error", "warning", "none" - * - * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail - * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes - * the "--local" option), the warning is displayed but the build will not fail. - * - * DEFAULT VALUE: "warning" - */ - "logLevel": "warning" - - /** - * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), - * then the message will be written inside that file; otherwise, the message is instead logged according to - * the "logLevel" option. - * - * DEFAULT VALUE: false - */ - // "addToApiReportFile": false - } - - // "TS2551": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - /** - * Configures handling of messages reported by API Extractor during its analysis. - * - * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" - * - * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings - */ - "extractorMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - /** - * Configures handling of messages reported by the TSDoc parser when analyzing code comments. - * - * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "tsdocMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "tsdoc-link-tag-unescaped-text": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - } - } -} +/** + * Config file for API Extractor. For more info, please visit: https://api-extractor.com + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for + * standard settings to be shared across multiple projects. + * + * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains + * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be + * resolved using NodeJS require(). + * + * SUPPORTED TOKENS: none + * DEFAULT VALUE: "" + */ + // "extends": "./shared/api-extractor-base.json" + // "extends": "my-package/include/api-extractor-base.json" + + /** + * Determines the "" token that can be used with other config file settings. The project folder + * typically contains the tsconfig.json and package.json config files, but the path is user-defined. + * + * The path is resolved relative to the folder of the config file that contains the setting. + * + * The default value for "projectFolder" is the token "", which means the folder is determined by traversing + * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder + * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error + * will be reported. + * + * SUPPORTED TOKENS: + * DEFAULT VALUE: "" + */ + "projectFolder": "..", + + /** + * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor + * analyzes the symbols exported by this module. + * + * The file extension must be ".d.ts" and not ".ts". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + */ + "mainEntryPointFilePath": "/lib/index.d.ts", + + /** + * A list of NPM package names whose exports should be treated as part of this package. + * + * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", + * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part + * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly + * imports library2. To avoid this, we can specify: + * + * "bundledPackages": [ "library2" ], + * + * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been + * local files for library1. + */ + "bundledPackages": [], + + /** + * Determines how the TypeScript compiler engine will be invoked by API Extractor. + */ + "compiler": { + /** + * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * Note: This setting will be ignored if "overrideTsconfig" is used. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/tsconfig.json" + */ + "tsconfigFilePath": "/tsconfig.release.json" + /** + * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. + * The object must conform to the TypeScript tsconfig schema: + * + * http://json.schemastore.org/tsconfig + * + * If omitted, then the tsconfig.json file will be read from the "projectFolder". + * + * DEFAULT VALUE: no overrideTsconfig section + */ + // "overrideTsconfig": { + // . . . + // } + /** + * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended + * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when + * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses + * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. + * + * DEFAULT VALUE: false + */ + // "skipLibCheck": true, + }, + + /** + * Configures how the API report file (*.api.md) will be generated. + */ + "apiReport": { + /** + * (REQUIRED) Whether to generate an API report. + */ + "enabled": true, + + /** + * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce + * a full file path. + * + * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". + * + * SUPPORTED TOKENS: , + * DEFAULT VALUE: ".api.md" + */ + // "reportFileName": ".api.md", + + /** + * Specifies the folder where the API report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, + * e.g. for an API review. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/etc/" + */ + "reportFolder": "/docgen/etc/", + + /** + * Specifies the folder where the temporary report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * After the temporary file is written to disk, it is compared with the file in the "reportFolder". + * If they are different, a production build will fail. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/" + */ + "reportTempFolder": "/docgen/temp/" + }, + + /** + * Configures how the doc model file (*.api.json) will be generated. + */ + "docModel": { + /** + * (REQUIRED) Whether to generate a doc model file. + */ + "enabled": true, + + /** + * The output path for the doc model file. The file extension should be ".api.json". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/.api.json" + */ + "apiJsonFilePath": "/docgen/.api.json" + }, + + /** + * Configures how the .d.ts rollup file will be generated. + */ + "dtsRollup": { + /** + * (REQUIRED) Whether to generate the .d.ts rollup file. + */ + "enabled": true + + /** + * Specifies the output path for a .d.ts rollup file to be generated without any trimming. + * This file will include all declarations that are exported by the main entry point. + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/dist/.d.ts" + */ + // "untrimmedFilePath": "/dist/.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. + * This file will include only declarations that are marked as "@public" or "@beta". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "betaTrimmedFilePath": "/dist/-beta.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. + * This file will include only declarations that are marked as "@public". + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "publicTrimmedFilePath": "/dist/-public.d.ts", + + /** + * When a declaration is trimmed, by default it will be replaced by a code comment such as + * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the + * declaration completely. + * + * DEFAULT VALUE: false + */ + // "omitTrimmingComments": true + }, + + /** + * Configures how the tsdoc-metadata.json file will be generated. + */ + "tsdocMetadata": { + /** + * Whether to generate the tsdoc-metadata.json file. + * + * DEFAULT VALUE: true + */ + // "enabled": true, + /** + * Specifies where the TSDoc metadata file should be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", + * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup + * falls back to "tsdoc-metadata.json" in the package folder. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" + }, + + /** + * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files + * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. + * To use the OS's default newline kind, specify "os". + * + * DEFAULT VALUE: "crlf" + */ + // "newlineKind": "crlf", + + /** + * Configures how API Extractor reports error and warning messages produced during analysis. + * + * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. + */ + "messages": { + /** + * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing + * the input .d.ts files. + * + * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "compilerMessageReporting": { + /** + * Configures the default routing for messages that don't match an explicit rule in this table. + */ + "default": { + /** + * Specifies whether the message should be written to the the tool's output log. Note that + * the "addToApiReportFile" property may supersede this option. + * + * Possible values: "error", "warning", "none" + * + * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail + * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes + * the "--local" option), the warning is displayed but the build will not fail. + * + * DEFAULT VALUE: "warning" + */ + "logLevel": "warning" + + /** + * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), + * then the message will be written inside that file; otherwise, the message is instead logged according to + * the "logLevel" option. + * + * DEFAULT VALUE: false + */ + // "addToApiReportFile": false + } + + // "TS2551": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by API Extractor during its analysis. + * + * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" + * + * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings + */ + "extractorMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + } + + // "ae-extra-release-tag": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by the TSDoc parser when analyzing code comments. + * + * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "tsdocMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + } + + // "tsdoc-link-tag-unescaped-text": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + } + } +} diff --git a/integration_test/functions/src/index.ts b/integration_test/functions/src/index.ts index e8c6918a5..f43f5c036 100644 --- a/integration_test/functions/src/index.ts +++ b/integration_test/functions/src/index.ts @@ -118,10 +118,7 @@ async function updateRemoteConfig( function v1Tests(testId: string, accessToken: string): Array> { return [ // A database write to trigger the Firebase Realtime Database tests. - admin - .database() - .ref(`dbTests/${testId}/start`) - .set({ '.sv': 'timestamp' }), + admin.database().ref(`dbTests/${testId}/start`).set({ '.sv': 'timestamp' }), // A Pub/Sub publish to trigger the Cloud Pub/Sub tests. new PubSub() .topic('pubsubTests') @@ -139,11 +136,7 @@ function v1Tests(testId: string, accessToken: string): Array> { admin.auth().deleteUser(userRecord.uid); }), // A firestore write to trigger the Cloud Firestore tests. - admin - .firestore() - .collection('tests') - .doc(testId) - .set({ test: testId }), + admin.firestore().collection('tests').doc(testId).set({ test: testId }), // Invoke a callable HTTPS trigger. callHttpsTrigger('v1-callableTests', { foo: 'bar', testId }), // A Remote Config update to trigger the Remote Config tests. @@ -172,14 +165,8 @@ export const integrationTests: any = functions timeoutSeconds: 540, }) .https.onRequest(async (req: Request, resp: Response) => { - const testId = admin - .database() - .ref() - .push().key; - admin - .database() - .ref(`testRuns/${testId}/timestamp`) - .set(Date.now()); + const testId = admin.database().ref().push().key; + admin.database().ref(`testRuns/${testId}/timestamp`).set(Date.now()); const testIdRef = admin.database().ref(`testRuns/${testId}`); functions.logger.info('testId is: ', testId); fs.writeFile('/tmp/' + testId + '.txt', 'test', () => {}); diff --git a/package-lock.json b/package-lock.json index c4d06b6a6..352233d50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@types/express": "4.17.3", "cors": "^2.8.5", "express": "^4.17.1", - "lodash": "^4.17.14", "node-fetch": "^2.6.7" }, "bin": { @@ -26,7 +25,6 @@ "@types/chai": "^4.1.7", "@types/chai-as-promised": "^7.1.0", "@types/jsonwebtoken": "^8.3.2", - "@types/lodash": "^4.14.135", "@types/mocha": "^5.2.7", "@types/mock-require": "^2.0.0", "@types/nock": "^10.0.3", @@ -48,7 +46,7 @@ "nock": "^10.0.6", "node-fetch": "^2.6.7", "portfinder": "^1.0.28", - "prettier": "^1.18.2", + "prettier": "^2.7.1", "semver": "^7.3.5", "sinon": "^7.3.2", "ts-node": "^10.4.0", @@ -64,7 +62,7 @@ "node": ">=14.10.0" }, "peerDependencies": { - "firebase-admin": "^10.0.0" + "firebase-admin": "^10.0.0 || ^11.0.0" } }, "node_modules/@babel/code-frame": { @@ -1183,12 +1181,6 @@ "@types/node": "*" } }, - "node_modules/@types/lodash": { - "version": "4.14.182", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", - "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", - "dev": true - }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -3816,7 +3808,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash.camelcase": { "version": "4.3.0", @@ -4772,15 +4765,18 @@ } }, "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==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { - "node": ">=4" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/promise-polyfill": { @@ -7526,12 +7522,6 @@ "@types/node": "*" } }, - "@types/lodash": { - "version": "4.14.182", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", - "integrity": "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==", - "dev": true - }, "@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -9616,7 +9606,8 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "lodash.camelcase": { "version": "4.3.0", @@ -10403,9 +10394,9 @@ "dev": true }, "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, "promise-polyfill": { diff --git a/package.json b/package.json index 125df88fd..b1a2f520f 100644 --- a/package.json +++ b/package.json @@ -199,7 +199,7 @@ "nock": "^10.0.6", "node-fetch": "^2.6.7", "portfinder": "^1.0.28", - "prettier": "^1.18.2", + "prettier": "^2.7.1", "semver": "^7.3.5", "sinon": "^7.3.2", "ts-node": "^10.4.0", @@ -217,4 +217,4 @@ "engines": { "node": ">=14.10.0" } -} \ No newline at end of file +} diff --git a/spec/common/providers/identity.spec.ts b/spec/common/providers/identity.spec.ts index 592d14767..2473d41f1 100644 --- a/spec/common/providers/identity.spec.ts +++ b/spec/common/providers/identity.spec.ts @@ -120,7 +120,7 @@ describe('identity', () => { describe('isValidRequest', () => { it('should error on non-post', () => { - const req = ({ + const req = { method: 'GET', header: { 'Content-Type': 'application/json', @@ -130,13 +130,13 @@ describe('identity', () => { jwt: '1.2.3', }, }, - } as unknown) as express.Request; + } as unknown as express.Request; expect(identity.isValidRequest(req)).to.be.false; }); it('should error on bad Content-Type', () => { - const req = ({ + const req = { method: 'POST', header(val: string) { return 'text/css'; @@ -146,36 +146,36 @@ describe('identity', () => { jwt: '1.2.3', }, }, - } as unknown) as express.Request; + } as unknown as express.Request; expect(identity.isValidRequest(req)).to.be.false; }); it('should error without req body', () => { - const req = ({ + const req = { method: 'POST', header(val: string) { return 'application/json'; }, - } as unknown) as express.Request; + } as unknown as express.Request; expect(identity.isValidRequest(req)).to.be.false; }); it('should error without req body data', () => { - const req = ({ + const req = { method: 'POST', header(val: string) { return 'application/json'; }, body: {}, - } as unknown) as express.Request; + } as unknown as express.Request; expect(identity.isValidRequest(req)).to.be.false; }); it('should error without req body', () => { - const req = ({ + const req = { method: 'POST', header(val: string) { return 'application/json'; @@ -183,13 +183,13 @@ describe('identity', () => { body: { data: {}, }, - } as unknown) as express.Request; + } as unknown as express.Request; expect(identity.isValidRequest(req)).to.be.false; }); it('should not error on valid request', () => { - const req = ({ + const req = { method: 'POST', header(val: string) { return 'application/json'; @@ -199,7 +199,7 @@ describe('identity', () => { jwt: '1.2.3', }, }, - } as unknown) as express.Request; + } as unknown as express.Request; expect(identity.isValidRequest(req)).to.be.true; }); diff --git a/spec/v1/function-builder.spec.ts b/spec/v1/function-builder.spec.ts index caf0332e0..936297be9 100644 --- a/spec/v1/function-builder.spec.ts +++ b/spec/v1/function-builder.spec.ts @@ -147,7 +147,8 @@ describe('FunctionBuilder', () => { it('should throw an error if user chooses a failurePolicy which is neither an object nor a boolean', () => { expect(() => functions.runWith({ - failurePolicy: (1234 as unknown) as functions.RuntimeOptions['failurePolicy'], + failurePolicy: + 1234 as unknown as functions.RuntimeOptions['failurePolicy'], }) ).to.throw(Error, 'failurePolicy must be a boolean or an object'); }); @@ -155,7 +156,7 @@ describe('FunctionBuilder', () => { it('should throw an error if user chooses a failurePolicy.retry which is not an object', () => { expect(() => functions.runWith({ - failurePolicy: { retry: (1234 as unknown) as object }, + failurePolicy: { retry: 1234 as unknown as object }, }) ).to.throw(Error, 'failurePolicy.retry'); }); @@ -366,8 +367,7 @@ describe('FunctionBuilder', () => { expect(() => functions.runWith({ labels: { - key: - 'a-very-long-value-that-is-more-than-the-maximum-allowed-length-for-values', + key: 'a-very-long-value-that-is-more-than-the-maximum-allowed-length-for-values', }, }) ).to.throw(); diff --git a/spec/v1/providers/auth.spec.ts b/spec/v1/providers/auth.spec.ts index d440866e4..8c2ca9d93 100644 --- a/spec/v1/providers/auth.spec.ts +++ b/spec/v1/providers/auth.spec.ts @@ -276,9 +276,8 @@ describe('Auth Functions', () => { }); describe('#onDelete', () => { - const cloudFunctionDelete: CloudFunction = functions.handler.auth.user.onDelete( - (data: UserRecord) => data - ); + const cloudFunctionDelete: CloudFunction = + functions.handler.auth.user.onDelete((data: UserRecord) => data); it('should return an empty endpoint', () => { const cloudFunction = functions.handler.auth.user.onDelete(() => null); diff --git a/spec/v1/providers/database.spec.ts b/spec/v1/providers/database.spec.ts index 3891ae383..122d6cb9e 100644 --- a/spec/v1/providers/database.spec.ts +++ b/spec/v1/providers/database.spec.ts @@ -620,12 +620,7 @@ describe('Database Functions', () => { describe('#child(): DataSnapshot', () => { it('should work with multiple calls', () => { populate({ a: { b: { c: 'd' } } }); - expect( - subject - .child('a') - .child('b/c') - .val() - ).to.equal('d'); + expect(subject.child('a').child('b/c').val()).to.equal('d'); }); }); diff --git a/spec/v1/providers/firestore.spec.ts b/spec/v1/providers/firestore.spec.ts index 2bc094591..c1b79a1c5 100644 --- a/spec/v1/providers/firestore.spec.ts +++ b/spec/v1/providers/firestore.spec.ts @@ -600,8 +600,7 @@ describe('Firestore Functions', () => { }, { resource: { - name: - 'projects/pid/databases/(default)/documents/collection/123', + name: 'projects/pid/databases/(default)/documents/collection/123', }, } ) diff --git a/spec/v2/providers/alerts/alerts.spec.ts b/spec/v2/providers/alerts/alerts.spec.ts index 8c4741f43..24daed9e5 100644 --- a/spec/v2/providers/alerts/alerts.spec.ts +++ b/spec/v2/providers/alerts/alerts.spec.ts @@ -138,9 +138,8 @@ describe('alerts', () => { describe('getOptsAndAlertTypeAndApp', () => { it('should parse a string', () => { - const [opts, alertType, appId] = alerts.getOptsAndAlertTypeAndApp( - ALERT_TYPE - ); + const [opts, alertType, appId] = + alerts.getOptsAndAlertTypeAndApp(ALERT_TYPE); expect(opts).to.deep.equal({}); expect(alertType).to.equal(ALERT_TYPE); diff --git a/src/common/utilities/path.ts b/src/common/utilities/path.ts index 33e187f9e..337551eac 100644 --- a/src/common/utilities/path.ts +++ b/src/common/utilities/path.ts @@ -29,7 +29,5 @@ export function pathParts(path: string): string[] { * @param child A second path segment, in POSIX format. */ export function joinPath(base: string, child: string) { - return pathParts(base) - .concat(pathParts(child)) - .join('/'); + return pathParts(base).concat(pathParts(child)).join('/'); } diff --git a/src/logger/compat.ts b/src/logger/compat.ts index f001a95a4..3971757ad 100644 --- a/src/logger/compat.ts +++ b/src/logger/compat.ts @@ -25,7 +25,7 @@ import { CONSOLE_SEVERITY, UNPATCHED_CONSOLE } from './common'; /** @hidden */ function patchedConsole(severity: string): (data: any, ...args: any[]) => void { - return function(data: any, ...args: any[]): void { + return function (data: any, ...args: any[]): void { let message = format(data, ...args); if (severity === 'ERROR') { message = new Error(message).stack || message; diff --git a/src/v1/providers/database.ts b/src/v1/providers/database.ts index 6ae144c34..2e9c96284 100644 --- a/src/v1/providers/database.ts +++ b/src/v1/providers/database.ts @@ -294,7 +294,8 @@ export class RefBuilder { }; } -const resourceRegex = /^projects\/([^/]+)\/instances\/([a-zA-Z0-9-]+)\/refs(\/.+)?/; +const resourceRegex = + /^projects\/([^/]+)\/instances\/([a-zA-Z0-9-]+)\/refs(\/.+)?/; /** * Utility function to extract database reference from resource string diff --git a/src/v2/params/types.ts b/src/v2/params/types.ts index 9612dc8dc..84eec4b8d 100644 --- a/src/v2/params/types.ts +++ b/src/v2/params/types.ts @@ -64,9 +64,9 @@ export class Param { valueType: (this.constructor as typeof Param).valueType, }; if (this.options.default && typeof this.options.default !== 'string') { - out.default = (this.options.default as - | { toString?: () => string } - | undefined)?.toString?.(); + out.default = ( + this.options.default as { toString?: () => string } | undefined + )?.toString?.(); } return out as ParamSpec; From 620af0b06cd66cb246bef00afdcb83a7a366a64e Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 22 Aug 2022 09:51:49 -0700 Subject: [PATCH 12/63] Fix broken branch (#1193) * Fix broken test. * Fix package-lock.json --- package-lock.json | 35 +++++++++---------- .../fixtures/sources/commonjs-params/index.js | 16 ++++----- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index d739d07c4..ecd886261 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@types/express": "4.17.3", "cors": "^2.8.5", "express": "^4.17.1", - "lodash": "^4.17.14", "node-fetch": "^2.6.7" }, "bin": { @@ -26,7 +25,6 @@ "@types/chai": "^4.1.7", "@types/chai-as-promised": "^7.1.0", "@types/jsonwebtoken": "^8.3.2", - "@types/lodash": "^4.14.135", "@types/mocha": "^5.2.7", "@types/mock-require": "^2.0.0", "@types/nock": "^10.0.3", @@ -48,7 +46,7 @@ "nock": "^10.0.6", "node-fetch": "^2.6.7", "portfinder": "^1.0.28", - "prettier": "^1.18.2", + "prettier": "^2.7.1", "semver": "^7.3.5", "sinon": "^7.3.2", "ts-node": "^10.4.0", @@ -61,10 +59,10 @@ "yargs": "^15.3.1" }, "engines": { - "node": "^8.13.0 || >=10.10.0" + "node": ">=14.10.0" }, "peerDependencies": { - "firebase-admin": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" + "firebase-admin": "^10.0.0 || ^11.0.0" } }, "node_modules/@babel/code-frame": { @@ -1061,11 +1059,6 @@ "@types/node": "*" } }, - "node_modules/@types/lodash": { - "version": "4.14.182", - "dev": true, - "license": "MIT" - }, "node_modules/@types/long": { "version": "4.0.2", "dev": true, @@ -3427,6 +3420,7 @@ }, "node_modules/lodash": { "version": "4.17.21", + "dev": true, "license": "MIT" }, "node_modules/lodash.camelcase": { @@ -4285,14 +4279,18 @@ } }, "node_modules/prettier": { - "version": "1.19.1", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, "engines": { - "node": ">=4" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/promise-polyfill": { @@ -6627,10 +6625,6 @@ "@types/node": "*" } }, - "@types/lodash": { - "version": "4.14.182", - "dev": true - }, "@types/long": { "version": "4.0.2", "dev": true, @@ -8221,7 +8215,8 @@ } }, "lodash": { - "version": "4.17.21" + "version": "4.17.21", + "dev": true }, "lodash.camelcase": { "version": "4.3.0", @@ -8818,7 +8813,9 @@ "dev": true }, "prettier": { - "version": "1.19.1", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, "promise-polyfill": { diff --git a/spec/fixtures/sources/commonjs-params/index.js b/spec/fixtures/sources/commonjs-params/index.js index d038a2f77..57d2fa361 100644 --- a/spec/fixtures/sources/commonjs-params/index.js +++ b/spec/fixtures/sources/commonjs-params/index.js @@ -1,21 +1,21 @@ -const functions = require("../../../../src/index"); -const functionsv2 = require("../../../../src/v2/index"); -const { defineString } = require("../../../../src/v2/params"); +const functions = require('../../../../src/v1/index'); +const functionsv2 = require('../../../../src/v2/index'); +const { defineString } = require('../../../../src/v2/params'); -defineString("FOO"); +defineString('FOO'); exports.v1http = functions.https.onRequest((req, resp) => { - resp.status(200).send("PASS"); + resp.status(200).send('PASS'); }); exports.v1callable = functions.https.onCall(() => { - return "PASS"; + return 'PASS'; }); exports.v2http = functionsv2.https.onRequest((req, resp) => { - resp.status(200).send("PASS"); + resp.status(200).send('PASS'); }); exports.v2callable = functionsv2.https.onCall(() => { - return "PASS"; + return 'PASS'; }); From 0e1f6886c505eae5819778294d84a917cdd2152c Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 22 Aug 2022 13:15:08 -0700 Subject: [PATCH 13/63] Fix bug where callable function skipped unrecognized auth headers (#1181) We have a weird edge case where an authorization in form we don't recognize will completely skip the auth check. The fix here applies 2 changes: 1) We allow 'Bearer ' format to be case insensitive. 'bearer ' also works. 2) We reject other authorization header. e.g. 'Beaver ' is rejected. --- spec/common/providers/https.spec.ts | 547 ++++++++++++++++------------ src/common/providers/https.ts | 37 +- 2 files changed, 332 insertions(+), 252 deletions(-) diff --git a/spec/common/providers/https.spec.ts b/spec/common/providers/https.spec.ts index 052c05226..20b261952 100644 --- a/spec/common/providers/https.spec.ts +++ b/spec/common/providers/https.spec.ts @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { App, deleteApp, initializeApp } from 'firebase-admin/app'; import * as sinon from 'sinon'; +import * as nock from 'nock'; import { getApp, setApp } from '../../../src/common/app'; import * as debug from '../../../src/common/debug'; @@ -286,269 +287,149 @@ describe('onCallHandler', () => { }); }); - it('should handle auth', async () => { - const mock = mockFetchPublicKeys(); - const projectId = getApp().options.projectId; - const idToken = generateIdToken(projectId); - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { - authorization: 'Bearer ' + idToken, - }), - expectedData: null, - callableFunction: (data, context) => { - checkAuthContext(context, projectId, mocks.user_id); - return null; - }, - callableFunction2: (request) => { - checkAuthContext(request, projectId, mocks.user_id); - return null; - }, - expectedHttpResponse: { - status: 200, - headers: expectedResponseHeaders, - body: { result: null }, - }, - }); - mock.done(); - }); + describe('auth', () => { + let mock: nock.Scope; - it('should reject bad auth', async () => { - const projectId = getApp().options.projectId; - const idToken = generateUnsignedIdToken(projectId); - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { - authorization: 'Bearer ' + idToken, - }), - expectedData: null, - callableFunction: (data, context) => { - return; - }, - callableFunction2: (request) => { - return; - }, - expectedHttpResponse: { - status: 401, - headers: expectedResponseHeaders, - body: { - error: { - status: 'UNAUTHENTICATED', - message: 'Unauthenticated', - }, - }, - }, + before(() => { + mock = mockFetchPublicKeys(); }); - }); - it('should handle AppCheck token', async () => { - const mock = mockFetchAppCheckPublicJwks(); - const projectId = getApp().options.projectId; - const appId = '123:web:abc'; - const appCheckToken = generateAppCheckToken(projectId, appId); - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { appCheckToken }), - expectedData: null, - callableFunction: (data, context) => { - checkAppCheckContext(context, projectId, appId); - return null; - }, - callableFunction2: (request) => { - checkAppCheckContext(request, projectId, appId); - return null; - }, - expectedHttpResponse: { - status: 200, - headers: expectedResponseHeaders, - body: { result: null }, - }, + after(() => { + mock.done(); }); - expect(mock.isDone()).to.be.true; - }); - - it('should reject bad AppCheck token', async () => { - const projectId = getApp().options.projectId; - const appId = '123:web:abc'; - const appCheckToken = generateUnsignedAppCheckToken(projectId, appId); - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { appCheckToken }), - callableOption: { - cors: { origin: true, methods: 'POST' }, - enforceAppCheck: true, - }, - expectedData: null, - callableFunction: (data, context) => { - return; - }, - callableFunction2: (request) => { - return; - }, - expectedHttpResponse: { - status: 401, - headers: expectedResponseHeaders, - body: { - error: { - status: 'UNAUTHENTICATED', - message: 'Unauthenticated', - }, + + it('should handle auth', async () => { + const projectId = getApp().options.projectId; + const idToken = generateIdToken(projectId); + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + authorization: 'Bearer ' + idToken, + }), + expectedData: null, + callableFunction: (data, context) => { + checkAuthContext(context, projectId, mocks.user_id); + return null; }, - }, + callableFunction2: (request) => { + checkAuthContext(request, projectId, mocks.user_id); + return null; + }, + expectedHttpResponse: { + status: 200, + headers: expectedResponseHeaders, + body: { result: null }, + }, + }); }); - }); - it('should handle bad AppCheck token with enforcement disabled', async () => { - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { - appCheckToken: 'FAKE', - }), - expectedData: null, - callableFunction: (data, context) => { - return; - }, - callableFunction2: (request) => { - return; - }, - callableOption: { - cors: { origin: true, methods: 'POST' }, - enforceAppCheck: false, - }, - expectedHttpResponse: { - status: 200, - headers: expectedResponseHeaders, - body: { result: null }, - }, + it('should handle auth - case insensitive', async () => { + const projectId = getApp().options.projectId; + const idToken = generateIdToken(projectId); + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + authorization: 'bearer ' + idToken, + }), + expectedData: null, + callableFunction: (data, context) => { + checkAuthContext(context, projectId, mocks.user_id); + return null; + }, + callableFunction2: (request) => { + checkAuthContext(request, projectId, mocks.user_id); + return null; + }, + expectedHttpResponse: { + status: 200, + headers: expectedResponseHeaders, + body: { result: null }, + }, + }); }); - }); - it('should handle bad AppCheck token with enforcement enabled', async () => { - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { - appCheckToken: 'FAKE', - }), - expectedData: null, - callableFunction: (data, context) => { - return; - }, - callableFunction2: (request) => { - return; - }, - callableOption: { - cors: { origin: true, methods: 'POST' }, - enforceAppCheck: true, - }, - expectedHttpResponse: { - status: 401, - headers: expectedResponseHeaders, - body: { - error: { - message: 'Unauthenticated', - status: 'UNAUTHENTICATED', + it('should reject auth with incorrect authorization header', async () => { + const projectId = getApp().options.projectId; + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + authorization: 'Beaver heyyall', + }), + expectedData: null, + callableFunction: (data, context) => { + checkAuthContext(context, projectId, mocks.user_id); + return null; + }, + callableFunction2: (request) => { + checkAuthContext(request, projectId, mocks.user_id); + return null; + }, + expectedHttpResponse: { + status: 401, + headers: expectedResponseHeaders, + body: { + error: { + status: 'UNAUTHENTICATED', + message: 'Unauthenticated', + }, }, }, - }, + }); }); - }); - it('should handle no AppCheck token with enforcement enabled', async () => { - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { - appCheckToken: 'MISSING', - }), - expectedData: null, - callableFunction: (data, context) => { - return; - }, - callableFunction2: (request) => { - return; - }, - callableOption: { - cors: { origin: true, methods: 'POST' }, - enforceAppCheck: true, - }, - expectedHttpResponse: { - status: 401, - headers: expectedResponseHeaders, - body: { - error: { - message: 'Unauthenticated', - status: 'UNAUTHENTICATED', + it('should reject bad auth with bad signature', async () => { + const projectId = getApp().options.projectId; + const idToken = generateUnsignedIdToken(projectId); + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + authorization: 'Bearer ' + idToken, + }), + expectedData: null, + callableFunction: (data, context) => { + return; + }, + callableFunction2: (request) => { + return; + }, + expectedHttpResponse: { + status: 401, + headers: expectedResponseHeaders, + body: { + error: { + status: 'UNAUTHENTICATED', + message: 'Unauthenticated', + }, }, }, - }, - }); - }); - - it('should handle instance id', async () => { - await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { - instanceIdToken: 'iid-token', - }), - expectedData: null, - callableFunction: (data, context) => { - expect(context.auth).to.be.undefined; - expect(context.instanceIdToken).to.equal('iid-token'); - return null; - }, - callableFunction2: (request) => { - expect(request.auth).to.be.undefined; - expect(request.instanceIdToken).to.equal('iid-token'); - return null; - }, - expectedHttpResponse: { - status: 200, - headers: expectedResponseHeaders, - body: { result: null }, - }, + }); }); }); - it('should expose raw request', async () => { - const mockReq = mockRequest(null, 'application/json', {}); - await runCallableTest({ - httpRequest: mockReq, - expectedData: null, - callableFunction: (data, context) => { - expect(context.rawRequest).to.not.be.undefined; - expect(context.rawRequest).to.equal(mockReq); - return null; - }, - callableFunction2: (request) => { - expect(request.rawRequest).to.not.be.undefined; - expect(request.rawRequest).to.equal(mockReq); - return null; - }, - expectedHttpResponse: { - status: 200, - headers: expectedResponseHeaders, - body: { result: null }, - }, - }); - }); + describe('AppCheck', () => { + let mock: nock.Scope; - describe('skip token verification debug mode support', () => { before(() => { - sinon - .stub(debug, 'isDebugFeatureEnabled') - .withArgs('skipTokenVerification') - .returns(true); + mock = mockFetchAppCheckPublicJwks(); }); after(() => { - sinon.verifyAndRestore(); + mock.done(); }); - it('should skip auth token verification', async () => { + it('should handle AppCheck token', async () => { const projectId = getApp().options.projectId; - const idToken = generateUnsignedIdToken(projectId); + const appId = '123:web:abc'; + const appCheckToken = generateAppCheckToken(projectId, appId); await runCallableTest({ - httpRequest: mockRequest(null, 'application/json', { - authorization: 'Bearer ' + idToken, - }), + httpRequest: mockRequest(null, 'application/json', { appCheckToken }), expectedData: null, + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: true, + }, callableFunction: (data, context) => { - checkAuthContext(context, projectId, mocks.user_id); + checkAppCheckContext(context, projectId, appId); return null; }, callableFunction2: (request) => { - checkAuthContext(request, projectId, mocks.user_id); + checkAppCheckContext(request, projectId, appId); return null; }, expectedHttpResponse: { @@ -559,19 +440,134 @@ describe('onCallHandler', () => { }); }); - it('should skip app check token verification', async () => { + it('should reject bad AppCheck token', async () => { const projectId = getApp().options.projectId; const appId = '123:web:abc'; const appCheckToken = generateUnsignedAppCheckToken(projectId, appId); await runCallableTest({ httpRequest: mockRequest(null, 'application/json', { appCheckToken }), expectedData: null, + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: true, + }, callableFunction: (data, context) => { - checkAppCheckContext(context, projectId, appId); + return; + }, + callableFunction2: (request) => { + return; + }, + expectedHttpResponse: { + status: 401, + headers: expectedResponseHeaders, + body: { + error: { + status: 'UNAUTHENTICATED', + message: 'Unauthenticated', + }, + }, + }, + }); + }); + + it('should handle bad AppCheck token with enforcement disabled', async () => { + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + appCheckToken: 'FAKE', + }), + expectedData: null, + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: false, + }, + callableFunction: (data, context) => { + expect(context.app).to.be.undefined; + return; + }, + callableFunction2: (request) => { + expect(request.app).to.be.undefined; + return; + }, + expectedHttpResponse: { + status: 200, + headers: expectedResponseHeaders, + body: { result: null }, + }, + }); + }); + + it('should handle bad AppCheck token with enforcement enabled', async () => { + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + appCheckToken: 'FAKE', + }), + expectedData: null, + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: true, + }, + callableFunction: (data, context) => { + return; + }, + callableFunction2: (request) => { + return; + }, + expectedHttpResponse: { + status: 401, + headers: expectedResponseHeaders, + body: { + error: { + message: 'Unauthenticated', + status: 'UNAUTHENTICATED', + }, + }, + }, + }); + }); + + it('should handle no AppCheck token with enforcement enabled', async () => { + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + appCheckToken: 'MISSING', + }), + expectedData: null, + callableFunction: (data, context) => { + return; + }, + callableFunction2: (request) => { + return; + }, + callableOption: { + cors: { origin: true, methods: 'POST' }, + enforceAppCheck: true, + }, + expectedHttpResponse: { + status: 401, + headers: expectedResponseHeaders, + body: { + error: { + message: 'Unauthenticated', + status: 'UNAUTHENTICATED', + }, + }, + }, + }); + }); + + it('should handle instance id', async () => { + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + instanceIdToken: 'iid-token', + }), + expectedData: null, + callableFunction: (data, context) => { + expect(context.auth).to.be.undefined; + expect(context.instanceIdToken).to.equal('iid-token'); return null; }, callableFunction2: (request) => { - checkAppCheckContext(request, projectId, appId); + expect(request.auth).to.be.undefined; + expect(request.instanceIdToken).to.equal('iid-token'); return null; }, expectedHttpResponse: { @@ -581,6 +577,89 @@ describe('onCallHandler', () => { }, }); }); + + it('should expose raw request', async () => { + const mockReq = mockRequest(null, 'application/json', {}); + await runCallableTest({ + httpRequest: mockReq, + expectedData: null, + callableFunction: (data, context) => { + expect(context.rawRequest).to.not.be.undefined; + expect(context.rawRequest).to.equal(mockReq); + return null; + }, + callableFunction2: (request) => { + expect(request.rawRequest).to.not.be.undefined; + expect(request.rawRequest).to.equal(mockReq); + return null; + }, + expectedHttpResponse: { + status: 200, + headers: expectedResponseHeaders, + body: { result: null }, + }, + }); + }); + + describe('skip token verification debug mode support', () => { + before(() => { + sinon + .stub(debug, 'isDebugFeatureEnabled') + .withArgs('skipTokenVerification') + .returns(true); + }); + + after(() => { + sinon.verifyAndRestore(); + }); + + it('should skip auth token verification', async () => { + const projectId = getApp().options.projectId; + const idToken = generateUnsignedIdToken(projectId); + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { + authorization: 'Bearer ' + idToken, + }), + expectedData: null, + callableFunction: (data, context) => { + checkAuthContext(context, projectId, mocks.user_id); + return null; + }, + callableFunction2: (request) => { + checkAuthContext(request, projectId, mocks.user_id); + return null; + }, + expectedHttpResponse: { + status: 200, + headers: expectedResponseHeaders, + body: { result: null }, + }, + }); + }); + + it('should skip app check token verification', async () => { + const projectId = getApp().options.projectId; + const appId = '123:web:abc'; + const appCheckToken = generateUnsignedAppCheckToken(projectId, appId); + await runCallableTest({ + httpRequest: mockRequest(null, 'application/json', { appCheckToken }), + expectedData: null, + callableFunction: (data, context) => { + checkAppCheckContext(context, projectId, appId); + return null; + }, + callableFunction2: (request) => { + checkAppCheckContext(request, projectId, appId); + return null; + }, + expectedHttpResponse: { + status: 200, + headers: expectedResponseHeaders, + body: { result: null }, + }, + }); + }); + }); }); }); diff --git a/src/common/providers/https.ts b/src/common/providers/https.ts index 85a760298..fdf842101 100644 --- a/src/common/providers/https.ts +++ b/src/common/providers/https.ts @@ -584,25 +584,26 @@ export async function checkAuthToken( if (!authorization) { return 'MISSING'; } - const match = authorization.match(/^Bearer (.*)$/); - if (match) { - const idToken = match[1]; - try { - let authToken: DecodedIdToken; - if (isDebugFeatureEnabled('skipTokenVerification')) { - authToken = unsafeDecodeIdToken(idToken); - } else { - authToken = await getAuth(getApp()).verifyIdToken(idToken); - } - ctx.auth = { - uid: authToken.uid, - token: authToken, - }; - return 'VALID'; - } catch (err) { - logger.warn('Failed to validate auth token.', err); - return 'INVALID'; + const match = authorization.match(/^Bearer (.*)$/i); + if (!match) { + return 'INVALID'; + } + const idToken = match[1]; + try { + let authToken: DecodedIdToken; + if (isDebugFeatureEnabled('skipTokenVerification')) { + authToken = unsafeDecodeIdToken(idToken); + } else { + authToken = await getAuth(getApp()).verifyIdToken(idToken); } + ctx.auth = { + uid: authToken.uid, + token: authToken, + }; + return 'VALID'; + } catch (err) { + logger.warn('Failed to validate auth token.', err); + return 'INVALID'; } } From 87d27ef29f7e8a21832046ada669604c0ce989f6 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 22 Aug 2022 16:11:37 -0700 Subject: [PATCH 14/63] Migrate from prettier to eslint to match firebase/firebase-tools styling (#1194) Let's bite the bullet - match styling of firebase/firebase-tools and start using eslint over prettier. This change effectively touches almost all files in this repo, especially since eslint prefers double-quotes over single-quotes. I've made couple of other changes to make eslint errors go away. Things like: 1) Eliminate dangling promises 2) Remove empty function definition (prefer `()=>undefined` over `()=>{}`) 3) Remove unused arguments from function definitions In theory, these are just linter changes without changes to the runtime behavior. v4 launches will need good tests and bugbash anyway, so this feels like a great time to commit to this migration. --- .eslintignore | 11 + .eslintrc.js | 77 + .github/ISSUE_TEMPLATE/---report-a-bug.md | 8 +- .github/workflows/postmerge.yaml | 10 +- .github/workflows/test.yaml | 26 +- .mocharc.yaml | 4 +- .prettierignore | 7 +- .prettierrc | 5 - .prettierrc.js | 3 + README.md | 16 +- integration_test/functions/src/index.ts | 134 +- integration_test/functions/src/region.ts | 2 +- integration_test/functions/src/testing.ts | 34 +- mocha/setup.ts | 6 +- package-lock.json | 3247 +++++++++++++++++--- package.json | 24 +- scripts/bin-test/mocha-setup.ts | 4 +- scripts/bin-test/test.ts | 120 +- scripts/publish-container/cloudbuild.yaml | 6 +- scripts/publish/cloudbuild.yaml | 130 +- spec/common/change.spec.ts | 72 +- spec/common/config.spec.ts | 42 +- spec/common/encoding.spec.ts | 48 +- spec/common/providers/https.spec.ts | 372 ++- spec/common/providers/identity.spec.ts | 662 ++-- spec/common/providers/tasks.spec.ts | 120 +- spec/common/utilities/path-pattern.spec.ts | 136 +- spec/common/utilities/path.spec.ts | 26 +- spec/helper.ts | 21 +- spec/logger.spec.ts | 108 +- spec/runtime/loader.spec.ts | 194 +- src/bin/firebase-functions.ts | 33 +- src/common/app.ts | 30 +- src/common/change.ts | 24 +- src/common/config.ts | 23 +- src/common/debug.ts | 4 +- src/common/encoding.ts | 11 +- src/common/providers/database.ts | 48 +- src/common/providers/https.ts | 285 +- src/common/providers/identity.ts | 212 +- src/common/providers/tasks.ts | 29 +- src/common/utilities/assertions.ts | 4 +- src/common/utilities/encoder.ts | 2 +- src/common/utilities/path-pattern.ts | 41 +- src/common/utilities/path.ts | 10 +- src/common/utilities/utils.ts | 7 +- src/runtime/loader.ts | 47 +- src/runtime/manifest.ts | 8 +- src/types/global.d.ts | 1 + tsconfig.json | 2 +- 50 files changed, 4377 insertions(+), 2119 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.js delete mode 100644 .prettierrc create mode 100644 .prettierrc.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..c939c9a1b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,11 @@ +coverage +dev +lib +node_modules +docgen +v1 +v2 +logger +dist +spec/fixtures +scripts/**/*.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..371dc4b0c --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,77 @@ +module.exports = { + env: { + es6: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:jsdoc/recommended", + "google", + "prettier", + ], + rules: { + "jsdoc/newline-after-description": "off", + "jsdoc/require-jsdoc": ["warn", { publicOnly: true }], + "no-restricted-globals": ["error", "name", "length"], + "prefer-arrow-callback": "error", + "prettier/prettier": "error", + "require-atomic-updates": "off", // This rule is so noisy and isn't useful: https://github.com/eslint/eslint/issues/11899 + "require-jsdoc": "off", // This rule is deprecated and superseded by jsdoc/require-jsdoc. + "valid-jsdoc": "off", // This is deprecated but included in recommended configs. + + "no-prototype-builtins": "warn", + "no-useless-escape": "warn", + "prefer-promise-reject-errors": "warn", + }, + overrides: [ + { + files: ["*.ts"], + rules: { + "jsdoc/require-param-type": "off", + "jsdoc/require-returns-type": "off", + + // Google style guide allows us to omit trivial parameters and returns + "jsdoc/require-param": "off", + "jsdoc/require-returns": "off", + + "@typescript-eslint/no-invalid-this": "error", + "@typescript-eslint/no-unused-vars": "error", // Unused vars should not exist. + "@typescript-eslint/no-misused-promises": "warn", // rule does not work with async handlers for express. + "no-invalid-this": "off", // Turned off in favor of @typescript-eslint/no-invalid-this. + "no-unused-vars": "off", // Off in favor of @typescript-eslint/no-unused-vars. + eqeqeq: ["error", "always", { null: "ignore" }], + camelcase: ["error", { properties: "never" }], // snake_case allowed in properties iif to satisfy an external contract / style + + // Ideally, all these warning should be error - let's fix them in the future. + "@typescript-eslint/no-unsafe-argument": "warn", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-unsafe-call": "warn", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-return": "warn", + "@typescript-eslint/restrict-template-expressions": "warn", + }, + }, + { + files: ["*.spec.*"], + env: { + mocha: true, + }, + rules: {}, + }, + ], + globals: {}, + parserOptions: { + project: "tsconfig.json", + }, + plugins: ["prettier", "@typescript-eslint", "jsdoc"], + settings: { + jsdoc: { + tagNamePreference: { + returns: "return", + }, + }, + }, + parser: "@typescript-eslint/parser", +}; diff --git a/.github/ISSUE_TEMPLATE/---report-a-bug.md b/.github/ISSUE_TEMPLATE/---report-a-bug.md index 3ad82bf60..abffad1b7 100644 --- a/.github/ISSUE_TEMPLATE/---report-a-bug.md +++ b/.github/ISSUE_TEMPLATE/---report-a-bug.md @@ -1,9 +1,9 @@ --- -name: '⚠️ Report a Bug' +name: "⚠️ Report a Bug" about: Think you found a bug in the firebase-functions SDK? Report it here. Please do not use this form if your function is deployed successfully but not working as you expected. -title: '' -labels: '' -assignees: '' +title: "" +labels: "" +assignees: "" ---