diff --git a/.env b/.env new file mode 100644 index 000000000..cf297760b --- /dev/null +++ b/.env @@ -0,0 +1,18 @@ +# This is a label that will appear as a grouping in the Looker admin page +ACTION_HUB_LABEL=My Local Hub +# This value is used to generate the authorization token - it is not the token itself. +# Run `yarn generate-api-key` to get the value you paste into Looker. +ACTION_HUB_SECRET=mysecret +# This is the URL that will be used to access Action Hub from the outside world. +# That is, the URL of the reverse proxy / load balancer if you are using one. +# So the port here might be different from the PORT param +ACTION_HUB_BASE_URL=localhost:4430 +# This specifies the local port the service binds to. +PORT=8080 +# This is used for encryption functions. +# Can be generated with something like `openssl rand -hex 32` +CIPHER_MASTER=281243e09385f19773569e4d99d306065efb0cf0f6e3ca4c705571c173722c99 +# Use this in development to turn on debug logging +ACTION_HUB_DEBUG=1 +# Use this in development to filter the list of actions exposed to Looker +ACTION_WHITELIST=pagerduty \ No newline at end of file diff --git a/.env.example b/.env.example index 0e6322014..cf297760b 100644 --- a/.env.example +++ b/.env.example @@ -15,4 +15,4 @@ CIPHER_MASTER=281243e09385f19773569e4d99d306065efb0cf0f6e3ca4c705571c173722c99 # Use this in development to turn on debug logging ACTION_HUB_DEBUG=1 # Use this in development to filter the list of actions exposed to Looker -ACTION_WHITELIST=my_new_action_name,other_action_name \ No newline at end of file +ACTION_WHITELIST=pagerduty \ No newline at end of file diff --git a/.github/workflows/actions-ci.yml b/.github/workflows/actions-ci.yml index fd6a103ec..345291cb8 100644 --- a/.github/workflows/actions-ci.yml +++ b/.github/workflows/actions-ci.yml @@ -2,8 +2,6 @@ name: Actions CI on: pull_request: branches: - - main - - master push: branches: diff --git a/.github/workflows/scan-image.yml b/.github/workflows/scan-image.yml new file mode 100644 index 000000000..8f80eb81b --- /dev/null +++ b/.github/workflows/scan-image.yml @@ -0,0 +1,37 @@ +name: Build and scan image + +on: + workflow_dispatch: # manual trigger + + pull_request: + branches: + +concurrency: scan + +jobs: + build-image: + timeout-minutes: 20 + runs-on: ubuntu-latest + env: + IMAGE: tapad/looker-pd-action + steps: + - uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build Docker image + uses: docker/build-push-action@v3 + with: + push: false + load: true + tags: ${{ env.IMAGE }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Scan image + uses: Tapad/gha-container-scanner@1.0.0 + with: + container: ${{ env.IMAGE }}:latest + wiz_key_id: ${{ secrets.WIZ_KEY_ID }} + wiz_key_secret: ${{ secrets.WIZ_KEY_SECRET }} diff --git a/Dockerfile b/Dockerfile index ea0b16814..08c6a5362 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,13 @@ -FROM node:14.18.0 +FROM node:14.18.0-slim RUN mkdir -p /code WORKDIR /code COPY . /code -RUN yarn install --production && yarn cache clean +# RUN yarn config set "strict-ssl" false +RUN yarn install --production +RUN yarn cache clean RUN yarn build CMD ["yarn","start"] diff --git a/lib/actions/facebook/facebook_custom_audiences.js b/lib/actions/facebook/facebook_custom_audiences.js index c86d84742..ba0c2ac5a 100644 --- a/lib/actions/facebook/facebook_custom_audiences.js +++ b/lib/actions/facebook/facebook_custom_audiences.js @@ -187,3 +187,6 @@ if (process.env.FACEBOOK_CLIENT_ID const fcma = new FacebookCustomAudiencesAction(process.env.FACEBOOK_CLIENT_ID, process.env.FACEBOOK_CLIENT_SECRET); Hub.addAction(fcma); } +else { + winston.warn(`[Facebook Custom Audiences] Action not registered because required environment variables are missing.`); +} diff --git a/lib/actions/facebook/lib/api.d.ts b/lib/actions/facebook/lib/api.d.ts index b7ed47681..302197e0c 100644 --- a/lib/actions/facebook/lib/api.d.ts +++ b/lib/actions/facebook/lib/api.d.ts @@ -1,4 +1,4 @@ -export declare const API_VERSION = "v12.0"; +export declare const API_VERSION = "v14.0"; export declare const API_BASE_URL: string; export declare const CUSTOMER_LIST_SOURCE_TYPES: { USER_PROVIDED_ONLY: string; @@ -36,12 +36,9 @@ export declare const validFacebookHashCombinations: [(f: UserFields) => string, export default class FacebookCustomAudiencesApi { readonly accessToken: string; constructor(accessToken: string); + pagingResults(url: string): Promise; me(): Promise; - getBusinessAccountIds(): Promise<{ - name: string; - id: string; - }[]>; - getAdAccountsForBusiness(businessId: string): Promise<{ + getAdAccounts(): Promise<{ name: string; id: string; }[]>; diff --git a/lib/actions/facebook/lib/api.js b/lib/actions/facebook/lib/api.js index 1a75725c1..1dcf4c211 100644 --- a/lib/actions/facebook/lib/api.js +++ b/lib/actions/facebook/lib/api.js @@ -13,7 +13,7 @@ exports.validFacebookHashCombinations = exports.CUSTOMER_LIST_SOURCE_TYPES = exp const gaxios = require("gaxios"); const winston = require("winston"); const util_1 = require("./util"); -exports.API_VERSION = "v12.0"; +exports.API_VERSION = "v14.0"; exports.API_BASE_URL = `https://graph.facebook.com/${exports.API_VERSION}/`; exports.CUSTOMER_LIST_SOURCE_TYPES = { // Used by Facebook for unknown purposes. @@ -53,38 +53,32 @@ class FacebookCustomAudiencesApi { constructor(accessToken) { this.accessToken = accessToken; } - me() { + pagingResults(url) { return __awaiter(this, void 0, void 0, function* () { - return this.apiCall("GET", "me"); + let data = []; + let hasNext = true; + while (hasNext) { + const response = yield this.apiCall("GET", url); + data = [...data, ...response.data]; + if (!response.paging || !response.paging.next) { + hasNext = false; + } + else { + url = response.paging.next + .replace(exports.API_BASE_URL, "") + .replace(/access_token=.+?&/, ""); + } + } + return data; }); } - /*Sample response: - { - "businesses": { - "data": [ - { - "id": "496949287383810", - "name": "Cool Guys Moving LLC" - }, - { - "id": "104000277081747", - "name": "Western Analytics" - } - ], - } - "paging": ... - "id": "106332305032035" - }*/ - getBusinessAccountIds() { + me() { return __awaiter(this, void 0, void 0, function* () { - const response = yield this.apiCall("GET", "me?fields=businesses"); - const namesAndIds = response.businesses.data.map((businessMetadata) => ({ name: businessMetadata.name, id: businessMetadata.id })); - return namesAndIds; + return this.apiCall("GET", "me"); }); } /* Sample response: - { "data": [ { @@ -93,34 +87,50 @@ class FacebookCustomAudiencesApi { "id": "act_114108701688636" } ], - "paging": {} + "paging": { + "cursors": { + "before": "abcdef123", + "after": "abcdef456" + }, + "previous": "https://graph.facebook.com...&before=abcdef123", + "next": "https://graph.facebook.com...&after=abcdef456" + } } */ - getAdAccountsForBusiness(businessId) { + getAdAccounts() { return __awaiter(this, void 0, void 0, function* () { - const addAcountsForBusinessUrl = `${businessId}/owned_ad_accounts?fields=name,account_id`; - const response = yield this.apiCall("GET", addAcountsForBusinessUrl); - const namesAndIds = response.data.map((adAccountMetadata) => ({ name: adAccountMetadata.name, id: adAccountMetadata.account_id })); + const addAcountsUrl = `me/adaccounts?fields=name,account_id`; + const data = yield this.pagingResults(addAcountsUrl); + const namesAndIds = data + .map((adAccountMetadata) => ({ name: adAccountMetadata.name, id: adAccountMetadata.account_id })) + .sort(util_1.sortCompare); return namesAndIds; }); } /* Sample response: { - "data": [ - { - "name": "My new Custom Audience", - "id": "23837492450850533" + "data": [ + { + "name": "My new Custom Audience", + "id": "23837492450850533" + } + ], + "paging": { + "cursors": { + "before": "abcdef123", + "after": "abcdef456" + }, + "previous": "https://graph.facebook.com...&before=abcdef123", + "next": "https://graph.facebook.com...&after=abcdef456" } - ], - "paging":... } */ getCustomAudiences(adAccountId) { return __awaiter(this, void 0, void 0, function* () { const customAudienceUrl = `act_${adAccountId}/customaudiences?fields=name`; - const response = yield this.apiCall("GET", customAudienceUrl); - const namesAndIds = response.data + const data = yield this.pagingResults(customAudienceUrl); + const namesAndIds = data .map((customAudienceMetadata) => ({ name: customAudienceMetadata.name, id: customAudienceMetadata.id })) .sort(util_1.sortCompare); return namesAndIds; diff --git a/lib/actions/facebook/lib/executor.js b/lib/actions/facebook/lib/executor.js index e9d24bd39..636d00741 100644 --- a/lib/actions/facebook/lib/executor.js +++ b/lib/actions/facebook/lib/executor.js @@ -126,8 +126,8 @@ class FacebookCustomAudiencesExecutor { throw new Error("Cannot execute action without choosing an operation type."); } this.operationType = operationType; - if (!actionRequest.formParams.choose_business || !actionRequest.formParams.choose_ad_account) { - throw new Error("Cannot execute action without business id or ad account id."); + if (!actionRequest.formParams.choose_ad_account) { + throw new Error("Cannot execute action without ad account id."); } if (!actionRequest.formParams.choose_custom_audience && (operationType === "update_audience" || operationType === "replace_audience")) { throw new Error("Cannot update or replace without a custom audience id."); diff --git a/lib/actions/facebook/lib/form_builder.js b/lib/actions/facebook/lib/form_builder.js index 8bbc609d3..dfd534a1f 100644 --- a/lib/actions/facebook/lib/form_builder.js +++ b/lib/actions/facebook/lib/form_builder.js @@ -14,29 +14,11 @@ const Hub = require("../../../hub"); class FacebookFormBuilder { generateActionForm(actionRequest, facebookApi) { return __awaiter(this, void 0, void 0, function* () { - let businesses = []; let adAccounts = []; let customAudiences = []; - businesses = yield facebookApi.getBusinessAccountIds(); - if (actionRequest.formParams.choose_business === "reset") { - actionRequest.formParams = {}; - } + adAccounts = yield facebookApi.getAdAccounts(); const form = new Hub.ActionForm(); form.fields = [{ - label: "Choose a business", - name: "choose_business", - description: "You can start over by choosing \"Start over\" from this list.", - required: true, - interactive: true, - type: "select", - options: [ - { name: "reset", label: "Start over" }, - ...(yield this.generateOptionsFromNamesAndIds(businesses)), - ], - }]; - if (actionRequest.formParams.choose_business) { - adAccounts = yield facebookApi.getAdAccountsForBusiness(actionRequest.formParams.choose_business); - form.fields.push({ label: "Choose a Facebook ad account", name: "choose_ad_account", required: true, @@ -45,8 +27,7 @@ class FacebookFormBuilder { options: [ ...(yield this.generateOptionsFromNamesAndIds(adAccounts)), ], - }); - } + }]; if (actionRequest.formParams.choose_ad_account) { form.fields.push({ label: "Would you like to create a new audience, update existing, or replace existing?", diff --git a/lib/actions/facebook/lib/util.d.ts b/lib/actions/facebook/lib/util.d.ts index c12ac6e77..0102ac61b 100644 --- a/lib/actions/facebook/lib/util.d.ts +++ b/lib/actions/facebook/lib/util.d.ts @@ -8,4 +8,4 @@ export declare function getDayOfMonth(date: string | number): string; export declare function getYear(date: string | number): string; export declare function formatFullDate(dayOfMonth: string, month: string, year: string): string; export declare function isNullOrUndefined(a: any): true | undefined; -export declare function sortCompare(a: any, b: any): 1 | 0 | -1; +export declare function sortCompare(a: any, b: any): 1 | -1 | 0; diff --git a/lib/actions/firebase/firebase.d.ts b/lib/actions/firebase/firebase.d.ts deleted file mode 100644 index bceac5f6b..000000000 --- a/lib/actions/firebase/firebase.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as firebaseAdmin from "firebase-admin"; -import * as firebaseApp from "firebase-admin/app"; -import * as Hub from "../../hub"; -export declare class FirebaseAction extends Hub.Action { - static firebaseAdmin: firebaseApp.App; - static setFirebaseClient(): void; - name: string; - label: string; - iconName: string; - description: string; - minimumSupportedLookerVersion: string; - contentType: string; - notificationOptions: { - priority: string; - timeToLive: number; - contentAvailable: boolean; - mutableContent: boolean; - }; - params: never[]; - supportedActionTypes: Hub.ActionType[]; - supportedFormats: Hub.ActionFormat[]; - supportedFormattings: Hub.ActionFormatting[]; - supportedVisualizationFormattings: Hub.ActionVisualizationFormatting[]; - execute(request: Hub.ActionRequest): Promise; - verifyAndSendMessage(params: Hub.ParamMap, webhookId: string | undefined): Promise; - sendMessageToDevice(deviceId: string, webhookId: string | undefined, payload: firebaseAdmin.messaging.MessagingPayload, options?: firebaseAdmin.messaging.MessagingOptions): Promise; -} diff --git a/lib/actions/firebase/firebase.js b/lib/actions/firebase/firebase.js deleted file mode 100644 index 0ee911015..000000000 --- a/lib/actions/firebase/firebase.js +++ /dev/null @@ -1,169 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.FirebaseAction = void 0; -const firebaseAdmin = require("firebase-admin"); -const uuid_1 = require("uuid"); -const winston = require("winston"); -const Hub = require("../../hub"); -const LOG_PREFIX = "[Firebase]"; -class FirebaseAction extends Hub.Action { - constructor() { - super(...arguments); - this.name = "firebase"; - this.label = "Firebase"; - this.iconName = "firebase/firebase.png"; - this.description = "Use firebase to send push notifications to mobile."; - this.minimumSupportedLookerVersion = "22.3.0"; - this.contentType = "image/jpeg"; - this.notificationOptions = { - priority: "high", - timeToLive: 60 * 60 * 24, - contentAvailable: true, - mutableContent: true, - }; - this.params = []; - this.supportedActionTypes = [Hub.ActionType.Query]; - this.supportedFormats = [Hub.ActionFormat.JsonDetail]; - this.supportedFormattings = [Hub.ActionFormatting.Unformatted]; - this.supportedVisualizationFormattings = [Hub.ActionVisualizationFormatting.Noapply]; - } - static setFirebaseClient() { - var _a; - if (firebaseAdmin.apps.length === 0) { - FirebaseAction.firebaseAdmin = firebaseAdmin.initializeApp({ - credential: firebaseAdmin.credential.cert({ - projectId: process.env.FIREBASE_PROJECT_ID, - clientEmail: process.env.FIREBASE_CLIENT_EMAIL, - privateKey: (_a = process.env.FIREBASE_PRIVATE_KEY) === null || _a === void 0 ? void 0 : _a.replace(/\\n/g, "\n"), - }), - databaseURL: process.env.FIREBASE_DATABASE, - }); - } - } - execute(request) { - return __awaiter(this, void 0, void 0, function* () { - const response = new Hub.ActionResponse({ success: true }); - const webhookId = request.webhookId; - winston.info(`${LOG_PREFIX} Firebase action (v 16.06.2022) called.`, { webhookId }); - let data = {}; - if (request.formParams.data) { - data = request.formParams.data; - if (!data.alert_id) { - winston.warn(`${LOG_PREFIX} Need Valid AlertId.`, { webhookId }); - throw "Need Valid AlertId."; - } - } - else { - winston.warn(`${LOG_PREFIX} Need valid notification data.`, { webhookId }); - throw "Need valid notification data."; - } - yield this.verifyAndSendMessage(request.formParams, webhookId); - return new Hub.ActionResponse(response); - }); - } - verifyAndSendMessage(params, webhookId) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { - var _a; - const data = params.data; - if (!params.title) { - winston.warn(`${LOG_PREFIX} Needs a valid title.`, { webhookId }); - reject("Needs a valid title."); - } - if (!params.deviceIds) { - winston.warn(`${LOG_PREFIX} Device Ids not present.`, { webhookId }); - resolve(); - } - const notification = { - title: params.title, - body: `On ${data.dashboard_name}`, - }; - const notificationData = data; - const notificationOptions = this.notificationOptions; - notificationData.id = uuid_1.v4(); - if (params.timeToLive) { - notificationOptions.timeToLive = parseFloat(params.timeToLive); - } - if (params.priority) { - notificationOptions.priority = params.priority; - } - try { - const userObj = JSON.parse((_a = params.deviceIds) !== null && _a !== void 0 ? _a : "[]"); - const deviceIdObject = params.deviceIds; - if (deviceIdObject.length === 0) { - winston.warn(`${LOG_PREFIX} Device Id length is 0.`, { webhookId }); - resolve(); - } - for (const userDevices of userObj) { - const devices = userDevices; - for (const device of devices) { - if (device.device_id && device.user_id) { - const deviceId = device.device_id.toString(); - notificationData.user_id = device.user_id.toString(); - const payload = { - notification, - data: notificationData, - }; - try { - yield this.sendMessageToDevice(deviceId, webhookId, payload, notificationOptions); - } - catch (error) { - winston.error(`${LOG_PREFIX} Error in sendMessageToDevice. ${error.toString()} `, { webhookId }); - reject(error); - } - } - } - } - } - catch (error) { - winston.error(`${LOG_PREFIX} Error. ${error.toString()} `, { webhookId }); - reject(error); - } - resolve(); - })) - .catch((error) => { - winston.error(`${LOG_PREFIX} Error. ${error.toString()} `, { webhookId }); - throw error; - }); - }); - } - sendMessageToDevice(deviceId, webhookId, payload, options) { - return __awaiter(this, void 0, void 0, function* () { - return new Promise((resolve, reject) => { - FirebaseAction.setFirebaseClient(); - firebaseAdmin.messaging().sendToDevice(deviceId, payload, options) - .then((response) => { - winston.info(`${LOG_PREFIX} notification sent to firebase. ${JSON.stringify(response)}`, { webhookId }); - resolve(); - }) - .catch((error) => { - winston.error(`${LOG_PREFIX} notification sending failed to firebase. ${error.toString()} `, { webhookId }); - reject(error.message); - }); - }) - .catch((error) => { - throw error; - }); - }); - } -} -exports.FirebaseAction = FirebaseAction; -if (process.env.FIREBASE_PROJECT_ID - && process.env.FIREBASE_CLIENT_EMAIL - && process.env.FIREBASE_PRIVATE_KEY - && process.env.FIREBASE_DATABASE) { - Hub.addAction(new FirebaseAction()); - winston.warn(`${LOG_PREFIX} Action registered.`); -} -else { - winston.warn(`${LOG_PREFIX} Action not registered because required environment variables are missing.`); -} diff --git a/lib/actions/google/ads/customer_match.js b/lib/actions/google/ads/customer_match.js index b5182b5a4..5c1e50f1f 100644 --- a/lib/actions/google/ads/customer_match.js +++ b/lib/actions/google/ads/customer_match.js @@ -113,9 +113,10 @@ class GoogleAdsCustomerMatch extends Hub.OAuthAction { } log("error", "Form error toString:", err.toString()); log("error", "Form error JSON:", JSON.stringify(err)); - // AuthorizationError from API client - this occurs when request contains bad loginCid + targetCid combo + // AuthorizationError from API client - this occurs when request contains bad loginCid or targetCid if (err.code === "403") { - wrappedResp.errorPrefix = `Error loading target accounts: ${err.response.data.error.message}.` + wrappedResp.errorPrefix = `Error loading target account with request: ${err.response.request.responseURL}. ` + + `${err.response.data[0].error.details[0].errors[0].message}` + ` Please retry loading the form again with the correct login account. `; return wrappedResp.returnError(err); } diff --git a/lib/actions/google/ads/lib/ads_form_builder.d.ts b/lib/actions/google/ads/lib/ads_form_builder.d.ts index 54e6b2d26..df93a9fd8 100644 --- a/lib/actions/google/ads/lib/ads_form_builder.d.ts +++ b/lib/actions/google/ads/lib/ads_form_builder.d.ts @@ -130,6 +130,7 @@ export declare class GoogleAdsActionFormBuilder { private maybeSetLoginCustomer; private maybeSetTargetCustomer; private getLoginCidOptions; + private getCustomer; private getTargetCidOptions; private selectOptionForCustomer; private sortCustomersCompareFn; diff --git a/lib/actions/google/ads/lib/ads_form_builder.js b/lib/actions/google/ads/lib/ads_form_builder.js index 6d9bde977..3dd9d433b 100644 --- a/lib/actions/google/ads/lib/ads_form_builder.js +++ b/lib/actions/google/ads/lib/ads_form_builder.js @@ -255,7 +255,7 @@ class GoogleAdsActionFormBuilder { if (!this.loginCid) { return; } - this.loginCustomer = (yield this.apiClient.getCustomer(this.loginCid)); + this.loginCustomer = yield this.getCustomer(this.loginCid); }); } maybeSetTargetCustomer() { @@ -263,7 +263,7 @@ class GoogleAdsActionFormBuilder { if (!this.targetCid) { return; } - this.targetCustomer = (yield this.apiClient.getCustomer(this.targetCid)); + this.targetCustomer = yield this.getCustomer(this.targetCid); }); } getLoginCidOptions() { @@ -271,16 +271,8 @@ class GoogleAdsActionFormBuilder { const listCustomersResp = yield this.apiClient.listAccessibleCustomers(); const customerResourceNames = listCustomersResp.resourceNames; const customers = yield Promise.all(customerResourceNames.map((rn) => __awaiter(this, void 0, void 0, function* () { - return this.apiClient.getCustomer(rn) - // Now is a good place to coalesce the name, before we try to sort the list - .then((cust) => { - if (!cust.descriptiveName) { - cust.descriptiveName = "Untitled"; - } - return cust; - }) - // We expect some errors on this call because the list endpoint returns test accounts that aren't accessible - .catch((_) => undefined); + const clientCid = rn.replace("customers/", ""); + return this.getCustomer(clientCid).catch(() => undefined); // ignore any auth errors from draft accounts }))); const filteredCustomers = customers.filter(Boolean); const sortedCustomers = filteredCustomers.sort(this.sortCustomersCompareFn); @@ -288,6 +280,18 @@ class GoogleAdsActionFormBuilder { return selectOptions; }); } + getCustomer(cId) { + return __awaiter(this, void 0, void 0, function* () { + return yield this.apiClient.searchClientCustomers(cId) + .then((data) => { + const cust = data[0].results.filter((c) => c.customerClient.id === cId)[0].customerClient; + if (!cust.descriptiveName) { + cust.descriptiveName = "Untitled"; + } + return cust; + }); + }); + } getTargetCidOptions() { return __awaiter(this, void 0, void 0, function* () { if (!this.loginCustomer) { diff --git a/lib/actions/google/ads/lib/api_client.d.ts b/lib/actions/google/ads/lib/api_client.d.ts index 2aa19c398..e73e4eeeb 100644 --- a/lib/actions/google/ads/lib/api_client.d.ts +++ b/lib/actions/google/ads/lib/api_client.d.ts @@ -6,7 +6,6 @@ export declare class GoogleAdsApiClient { readonly loginCid?: string | undefined; constructor(log: Logger, accessToken: string, developerToken: string, loginCid?: string | undefined); listAccessibleCustomers(): Promise; - getCustomer(resourceNameOrId: string): Promise; searchOpenUserLists(clientCid: string, uploadKeyType: "MOBILE_ADVERTISING_ID" | "CONTACT_INFO"): Promise; searchClientCustomers(clientCid: string): Promise; createUserList(targetCid: string, newListName: string, newListDescription: string, uploadKeyType: "MOBILE_ADVERTISING_ID" | "CONTACT_INFO", mobileAppId?: string): Promise; diff --git a/lib/actions/google/ads/lib/api_client.js b/lib/actions/google/ads/lib/api_client.js index aa0cf0c46..39ddae0ad 100644 --- a/lib/actions/google/ads/lib/api_client.js +++ b/lib/actions/google/ads/lib/api_client.js @@ -27,13 +27,6 @@ class GoogleAdsApiClient { return this.apiCall(method, path); }); } - getCustomer(resourceNameOrId) { - return __awaiter(this, void 0, void 0, function* () { - const method = "GET"; - const path = resourceNameOrId.startsWith("customers/") ? resourceNameOrId : `customers/${resourceNameOrId}`; - return this.apiCall(method, path); - }); - } searchOpenUserLists(clientCid, uploadKeyType) { return __awaiter(this, void 0, void 0, function* () { const method = "POST"; @@ -55,7 +48,7 @@ class GoogleAdsApiClient { const method = "POST"; const path = `customers/${clientCid}/googleAds:searchStream`; const body = { - query: "SELECT\ + query: `SELECT\ customer_client.client_customer\ , customer_client.hidden\ , customer_client.id\ @@ -64,7 +57,9 @@ class GoogleAdsApiClient { , customer_client.test_account\ , customer_client.descriptive_name\ , customer_client.manager\ - FROM customer_client", + , customer_client.status\ + FROM customer_client\ + WHERE customer_client.status NOT IN ('CANCELED', 'SUSPENDED')`, }; return this.apiCall(method, path, body); }); @@ -148,7 +143,7 @@ class GoogleAdsApiClient { url, data, headers, - baseURL: "https://googleads.googleapis.com/v9/", + baseURL: "https://googleads.googleapis.com/v11/", }); if (process.env.ACTION_HUB_DEBUG) { const apiResponse = lodash.cloneDeep(response); diff --git a/lib/actions/google/drive/sheets/google_sheets.d.ts b/lib/actions/google/drive/sheets/google_sheets.d.ts index e99415be8..3781a4718 100644 --- a/lib/actions/google/drive/sheets/google_sheets.d.ts +++ b/lib/actions/google/drive/sheets/google_sheets.d.ts @@ -20,6 +20,7 @@ export declare class GoogleSheetsAction extends GoogleDriveAction { sendOverwriteData(filename: string, request: Hub.ActionRequest, drive: Drive, sheet: Sheet): Promise>; clearSheet(spreadsheetId: string, sheet: Sheet, sheetId: number): GaxiosPromise; resize(maxRows: number, sheet: Sheet, spreadsheetId: string, sheetId: number): Promise>; + sanitizeFilename(filename: string): string; flush(buffer: sheets_v4.Schema$BatchUpdateSpreadsheetRequest, sheet: Sheet, spreadsheetId: string, webhookId: string): Promise>; flushRetry(buffer: sheets_v4.Schema$BatchUpdateSpreadsheetRequest, sheet: Sheet, spreadsheetId: string): Promise>; protected delay(time: number): Promise; diff --git a/lib/actions/google/drive/sheets/google_sheets.js b/lib/actions/google/drive/sheets/google_sheets.js index 54fd706a0..b18d1af51 100644 --- a/lib/actions/google/drive/sheets/google_sheets.js +++ b/lib/actions/google/drive/sheets/google_sheets.js @@ -117,6 +117,7 @@ class GoogleSheetsAction extends google_drive_1.GoogleDriveAction { sendOverwriteData(filename, request, drive, sheet) { return __awaiter(this, void 0, void 0, function* () { const parents = request.formParams.folder ? [request.formParams.folder] : undefined; + filename = this.sanitizeFilename(filename); const options = { q: `name = '${filename}' and '${parents}' in parents and trashed=false`, fields: "files", @@ -303,6 +304,9 @@ class GoogleSheetsAction extends google_drive_1.GoogleDriveAction { }); }); } + sanitizeFilename(filename) { + return filename.split("'").join("\'"); + } flush(buffer, sheet, spreadsheetId, webhookId) { return __awaiter(this, void 0, void 0, function* () { return sheet.spreadsheets.batchUpdate({ spreadsheetId, requestBody: buffer }).catch((e) => __awaiter(this, void 0, void 0, function* () { diff --git a/lib/actions/index.d.ts b/lib/actions/index.d.ts index d7506dad0..a09c6e4ea 100644 --- a/lib/actions/index.d.ts +++ b/lib/actions/index.d.ts @@ -9,7 +9,6 @@ import "./digitalocean/digitalocean_droplet"; import "./digitalocean/digitalocean_object_storage"; import "./dropbox/dropbox"; import "./facebook/facebook_custom_audiences"; -import "./firebase/firebase"; import "./google/ads/customer_match"; import "./google/analytics/data_import"; import "./google/drive/google_drive"; @@ -21,6 +20,7 @@ import "./jira/jira"; import "./kloudio/kloudio"; import "./marketo/marketo"; import "./mparticle/mparticle"; +import "./pagerduty/pagerduty"; import "./queueaction/queue_action_for_testing"; import "./sagemaker/sagemaker"; import "./salesforce/campaigns/salesforce_campaigns"; diff --git a/lib/actions/index.js b/lib/actions/index.js index ed844c2d3..d406444a9 100644 --- a/lib/actions/index.js +++ b/lib/actions/index.js @@ -11,7 +11,6 @@ require("./digitalocean/digitalocean_droplet"); require("./digitalocean/digitalocean_object_storage"); require("./dropbox/dropbox"); require("./facebook/facebook_custom_audiences"); -require("./firebase/firebase"); require("./google/ads/customer_match"); require("./google/analytics/data_import"); require("./google/drive/google_drive"); @@ -23,6 +22,7 @@ require("./jira/jira"); require("./kloudio/kloudio"); require("./marketo/marketo"); require("./mparticle/mparticle"); +require("./pagerduty/pagerduty"); require("./queueaction/queue_action_for_testing"); require("./sagemaker/sagemaker"); require("./salesforce/campaigns/salesforce_campaigns"); diff --git a/lib/actions/pagerduty/pagerduty.d.ts b/lib/actions/pagerduty/pagerduty.d.ts new file mode 100644 index 000000000..856175f68 --- /dev/null +++ b/lib/actions/pagerduty/pagerduty.d.ts @@ -0,0 +1,21 @@ +import * as Hub from "../../hub"; +export declare class PagerDutyAction extends Hub.Action { + name: string; + label: string; + iconName: string; + description: string; + supportedActionTypes: Hub.ActionType[]; + requiredFields: never[]; + params: { + name: string; + label: string; + required: boolean; + description: string; + sensitive: boolean; + }[]; + usesStreaming: boolean; + execute(request: Hub.ActionRequest): Promise; + form(request: Hub.ActionRequest): Promise; + private getApiKey; + private parseResultSet; +} diff --git a/lib/actions/pagerduty/pagerduty.js b/lib/actions/pagerduty/pagerduty.js new file mode 100644 index 000000000..1f17dad3b --- /dev/null +++ b/lib/actions/pagerduty/pagerduty.js @@ -0,0 +1,113 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PagerDutyAction = void 0; +const Hub = require("../../hub"); +const pagerduty_client_1 = require("./pagerduty_client"); +const pagerduty_form_1 = require("./pagerduty_form"); +const winston = require("winston"); +class PagerDutyAction extends Hub.Action { + constructor() { + super(...arguments); + this.name = "pagerduty"; + this.label = "PagerDuty"; + this.iconName = "pagerduty/pd_icon.png"; + this.description = `PagerDuty (${process.env.ACTION_HUB_LABEL})`; + this.supportedActionTypes = [Hub.ActionType.Query, Hub.ActionType.Dashboard]; + this.requiredFields = []; + this.params = [{ + name: "pagerduty_api_key", + label: "PagerDuty API Key", + required: true, + description: `A PagerDuty API key used to authenticate with the PagerDuty REST API. For how to generate a key, please follow instructions at https://support.pagerduty.com/docs/generating-api-keys`, + sensitive: true, + }]; + this.usesStreaming = false; + } + execute(request) { + return __awaiter(this, void 0, void 0, function* () { + function validationError(e) { + console.warn(`Couldn't execute request: ${e.message}`); + return new Hub.ActionResponse({ message: 'Validation error', success: false, validationErrors: [e] }); + } + const form = pagerduty_form_1.PagerDutyForm.create(request.formParams); + const apiKey = this.getApiKey(request); + const resultSet = this.parseResultSet(request.attachment); + if (request.scheduledPlan == null) + return validationError({ field: '', message: 'PagerDuty action only available for schedule queries' }); + if (typeof apiKey !== "string") + return validationError(apiKey); + if (!Array.isArray(resultSet)) + return validationError(resultSet); + const trimmedResultset = resultSet.slice(0, form.max_incidents); + const incidents = form.createPagerDutyIncidents(trimmedResultset, request.scheduledPlan); + if (!Array.isArray(incidents)) + return validationError(incidents); + const client = new pagerduty_client_1.PagerDutyClient(apiKey); + return client.createIncidents(incidents, [form.service_key], form.schedule_id); + }); + } + form(request) { + return __awaiter(this, void 0, void 0, function* () { + const form = new Hub.ActionForm(); + const apiKey = this.getApiKey(request); + if (typeof apiKey !== "string") { + form.error = apiKey.message; + return form; + } + const client = new pagerduty_client_1.PagerDutyClient(apiKey); + // Call a remote endpoint to verify that the API key is correct + // The 'form' method is invoked when the API key is entered in the Looker admin configuration + const services = yield client.services(); + winston.info(`PagerDuty key validation OK. Found ${services.length} services.`); + form.fields = pagerduty_form_1.PagerDutyForm.formFields; + return form; + }); + } + getApiKey(request) { + const apiKey = request.params['pagerduty_api_key']; + if (apiKey == null) + return { + field: 'pagerduty_api_key', + message: "API Key not configured for Looker. Please configured it in the admin section." + }; + return apiKey; + } + parseResultSet(attachment) { + if (attachment == null) + return { + field: 'service_key', + message: "Please format data as JSON input, field not found 'attachment'" + }; + if (attachment.mime !== 'application/json') + return { + field: 'service_key', + message: `Please format data as JSON input. Expected MIME type 'application/json', got ${attachment.mime}` + }; + if (attachment.dataJSON == null) { + // Looker sent empty report + return []; + } + else { + if (Array.isArray(attachment.dataJSON)) + return attachment.dataJSON; + else if (Array.isArray(attachment.dataJSON.data)) + return attachment.dataJSON.data; + else + return { + field: 'service_key', + message: 'JSON array or object expected' + }; + } + } +} +exports.PagerDutyAction = PagerDutyAction; +Hub.addAction(new PagerDutyAction()); diff --git a/lib/actions/pagerduty/pagerduty_client.d.ts b/lib/actions/pagerduty/pagerduty_client.d.ts new file mode 100644 index 000000000..3be54c4f2 --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_client.d.ts @@ -0,0 +1,16 @@ +import { Service } from './service'; +import { PagerDutyCreateIncident } from './pagerduty_create_incident'; +import { PagerDutyIncident, PagerDutyAlert } from './pagerduty_incident'; +import * as Hub from "../../hub"; +export declare class PagerDutyClient { + private apiKey; + constructor(apiKey: string); + private PagerDutyEventApi; + private restApiClient; + services(): Promise; + incidents(service: Service): Promise; + alerts(incident: PagerDutyIncident): Promise; + createIncidents(incidents: PagerDutyCreateIncident[], serviceKeys: string[], scheduleId: string): Promise; + private getAlertsManagedByLooker; + private getAlertsToResolve; +} diff --git a/lib/actions/pagerduty/pagerduty_client.js b/lib/actions/pagerduty/pagerduty_client.js new file mode 100644 index 000000000..c37071f6d --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_client.js @@ -0,0 +1,137 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PagerDutyClient = void 0; +const got_1 = require("got"); +const pagerduty_create_incident_1 = require("./pagerduty_create_incident"); +const Hub = require("../../hub"); +const moment = require("moment"); +class PagerDutyClient { + constructor(apiKey) { + this.apiKey = apiKey; + this.PagerDutyEventApi = 'https://events.pagerduty.com/v2'; + this.restApiClient = got_1.default.extend({ + prefixUrl: 'https://api.pagerduty.com', + headers: { + 'Authorization': `Token token=${this.apiKey}`, + 'Accept': 'application/json' + } + }); + } + services() { + return __awaiter(this, void 0, void 0, function* () { + const res = yield this.restApiClient.get('services?include[]=integrations').json(); + return res.services; + }); + } + incidents(service) { + return __awaiter(this, void 0, void 0, function* () { + const res = yield this.restApiClient + .get(`incidents?include[]=incident_key&service_ids[]=${service.id}&statuses[]=triggered&statuses[]=acknowledged`) + .json(); + return res.incidents; + }); + } + alerts(incident) { + return __awaiter(this, void 0, void 0, function* () { + const res = yield this.restApiClient.get(`incidents/${incident.id}/alerts`).json(); + return res.alerts; + }); + } + createIncidents(incidents, serviceKeys, scheduleId) { + return __awaiter(this, void 0, void 0, function* () { + const newAlertKeys = incidents.map(i => i.dedup_key); + incidents.forEach(i => console.info(`Incident "${i.dedup_key}" received on routing key "${i.routing_key}"`)); + const activeAlertsPerRoutingKeyPromise = this.getAlertsManagedByLooker(serviceKeys, scheduleId) + .then(activeAlertsPerRoutingKey => { + activeAlertsPerRoutingKey.forEach(keyAndAlerts => { + keyAndAlerts.alerts.forEach(a => console.info(`Active alert "${a.alert_key}" on routing key "${keyAndAlerts.routingKey}"`)); + }); + return activeAlertsPerRoutingKey; + }); + const alertsToResolvePerRroutingKeyPromise = this.getAlertsToResolve(activeAlertsPerRoutingKeyPromise, newAlertKeys) + .then(alertsPerKeys => { + alertsPerKeys.forEach(alertsPerKey => alertsPerKey.alerts.forEach(alert => console.info(`Resolving "${alert.alert_key}" on routing key ${alertsPerKey.routingKey}`))); + return alertsPerKeys; + }); + const resolveAlertsPromise = alertsToResolvePerRroutingKeyPromise + .then(keysAndAlerts => keysAndAlerts.flatMap(keyAndAlerts => keyAndAlerts.alerts.map(alert => { + const resolveIncident = { + routing_key: keyAndAlerts.routingKey, + event_action: pagerduty_create_incident_1.PagerDutyEventAction.Resolve, + dedup_key: alert.alert_key, + payload: { + summary: "Looker auto-resolving alert", + severity: 'warning', + source: "Looker actions", + timestamp: moment().format(), + } + }; + return resolveIncident; + }))) + .then(incidents => Promise.all(incidents.map(incident => got_1.default.post(`${this.PagerDutyEventApi}/enqueue`, { + json: incident + })))); + const triggerAlertsPromises = Promise.all(incidents.map(i => got_1.default.post(`${this.PagerDutyEventApi}/enqueue`, { + json: i + }))); + return Promise.all([triggerAlertsPromises, resolveAlertsPromise]) + .then(r => { + const responses = r.reduce((a, b) => a.concat(b)); + const message = `Pushed ${responses.length} alerts (might be deduped) to PagerDuty`; + console.info(message); + return new Hub.ActionResponse({ success: true, message: message }); + }) + .catch(reason => { + const message = `Failed to create PD incidents ${reason}`; + console.error(message); + console.log(reason); + return new Hub.ActionResponse({ success: false, message: message }); + }); + }); + } + getAlertsManagedByLooker(serviceKeys, scheduleId) { + const keysAndIncidentsPromise = this.services() + .then(services => services + .flatMap(service => service.integrations.map(integration => { + const serviceAndIntegration = [service, integration]; + return serviceAndIntegration; + })) + .filter(serviceAndIntegration => serviceKeys.includes(serviceAndIntegration[1].integration_key)) + .map(serviceAndIntegration => { + const keysAndService = [serviceAndIntegration[1].integration_key, serviceAndIntegration[0]]; + return keysAndService; + })) + .then(keysAndServices => Promise.all(keysAndServices.map(keyAndService => this.incidents(keyAndService[1]).then(incidents => { + const keysAndIncidents = [keyAndService[0], incidents]; + return keysAndIncidents; + })))); + return keysAndIncidentsPromise + .then(keysAndIncidents => Promise.all(keysAndIncidents.flatMap(keyAndIncidents => keyAndIncidents[1].map(incident => this.alerts(incident).then(alerts => new AlertsPerRoutingKey(keyAndIncidents[0], + // TODO: Optional chaining added in TS 3.7 + alerts.filter(a => a.body && + a.body.details && + a.body.details.managed_by_looker && + a.body.details.auto_resolve && + a.body.details.schedule_id == scheduleId))))))); + } + getAlertsToResolve(activeAlertsPerRoutingKeyPromise, newAlertKeys) { + return activeAlertsPerRoutingKeyPromise + .then(keysAndAlerts => keysAndAlerts.map(keyAndAlerts => new AlertsPerRoutingKey(keyAndAlerts.routingKey, keyAndAlerts.alerts.filter(alert => !newAlertKeys.includes(alert.alert_key))))); + } +} +exports.PagerDutyClient = PagerDutyClient; +class AlertsPerRoutingKey { + constructor(routingKey, alerts) { + this.routingKey = routingKey; + this.alerts = alerts; + } +} diff --git a/lib/actions/pagerduty/pagerduty_create_incident.d.ts b/lib/actions/pagerduty/pagerduty_create_incident.d.ts new file mode 100644 index 000000000..4ff4ce2d0 --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_create_incident.d.ts @@ -0,0 +1,43 @@ +/** + * API reference: + * + * https://developer.pagerduty.com/api-reference/reference/events-v2/openapiv3.json/paths/~1enqueue/post + */ +export interface PagerDutyCreateIncident { + routing_key: string; + event_action: PagerDutyEventAction; + dedup_key: string; + payload?: PagerDutyCreateIncidentPayload; + client?: string; + client_url?: string; + links?: LinkParam[]; + images?: ImageParam[]; +} +export declare enum PagerDutyEventAction { + Trigger = "trigger", + Acknowledge = "acknowledge", + Resolve = "resolve" +} +export interface LinkParam { + href: string; + text: string; +} +export interface ImageParam { + src?: string; + href?: string; + alt?: string; +} +export interface PagerDutyCreateIncidentPayload { + summary: string; + severity: 'critical' | 'warning' | 'error' | 'info'; + source: string; + timestamp?: string; + component?: string; + group?: string; + custom_details?: CustomDetails; +} +export interface CustomDetails { + managed_by_looker: boolean; + auto_resolve: boolean; + schedule_id: string; +} diff --git a/lib/actions/pagerduty/pagerduty_create_incident.js b/lib/actions/pagerduty/pagerduty_create_incident.js new file mode 100644 index 000000000..531a193e7 --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_create_incident.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PagerDutyEventAction = void 0; +var PagerDutyEventAction; +(function (PagerDutyEventAction) { + PagerDutyEventAction["Trigger"] = "trigger"; + PagerDutyEventAction["Acknowledge"] = "acknowledge"; + PagerDutyEventAction["Resolve"] = "resolve"; +})(PagerDutyEventAction = exports.PagerDutyEventAction || (exports.PagerDutyEventAction = {})); diff --git a/lib/actions/pagerduty/pagerduty_form.d.ts b/lib/actions/pagerduty/pagerduty_form.d.ts new file mode 100644 index 000000000..d0f95c49b --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_form.d.ts @@ -0,0 +1,45 @@ +import * as Hub from '../../hub'; +import { PagerDutyCreateIncident } from './pagerduty_create_incident'; +import { ParamMap } from '../../hub'; +declare enum FormFields { + ServiceKeyKey = "service_key", + DeDeuplicationIdColumnKey = "deduplication_id_column", + ScheduleIdKey = "schdeule_id", + AutoResolveKey = "auto_resolution_boolean", + MaxIncidentsKey = "max_incidents", + Summary = "summary", + Severity = "severity", + Message = "message" +} +declare enum Severity { + Critical = "critical", + Error = "error", + Warning = "warning", + Info = "info" +} +interface IPagerDutyForm { + [FormFields.ServiceKeyKey]: string; + [FormFields.DeDeuplicationIdColumnKey]: string; + [FormFields.ScheduleIdKey]: string; + [FormFields.AutoResolveKey]: boolean; + [FormFields.MaxIncidentsKey]: number; + [FormFields.Summary]: string; + [FormFields.Message]: string; + [FormFields.Severity]: Severity; +} +export declare class PagerDutyForm { + service_key: string; + deduplication_id_column: string; + schedule_id: string; + auto_resolution_boolean: boolean; + max_incidents: number; + summary: string; + severity: Severity; + message: string; + static formFields: Hub.ActionFormField[]; + static jsonToInterface(json: ParamMap): IPagerDutyForm; + static create(json: ParamMap): PagerDutyForm; + constructor(service_key: string, deduplication_id_column: string, schedule_id: string, auto_resolution_boolean: boolean, max_incidents: number, summary: string, severity: Severity, message: string); + createPagerDutyIncidents(resultSet: any[], plan: Hub.ActionScheduledPlan): Hub.ValidationError | PagerDutyCreateIncident[]; +} +export {}; diff --git a/lib/actions/pagerduty/pagerduty_form.js b/lib/actions/pagerduty/pagerduty_form.js new file mode 100644 index 000000000..23e55b889 --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_form.js @@ -0,0 +1,147 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PagerDutyForm = void 0; +const pagerduty_create_incident_1 = require("./pagerduty_create_incident"); +const moment = require("moment"); +const Mustache = require("mustache"); +var FormFields; +(function (FormFields) { + FormFields["ServiceKeyKey"] = "service_key"; + FormFields["DeDeuplicationIdColumnKey"] = "deduplication_id_column"; + FormFields["ScheduleIdKey"] = "schdeule_id"; + FormFields["AutoResolveKey"] = "auto_resolution_boolean"; + FormFields["MaxIncidentsKey"] = "max_incidents"; + FormFields["Summary"] = "summary"; + FormFields["Severity"] = "severity"; + FormFields["Message"] = "message"; +})(FormFields || (FormFields = {})); +var Severity; +(function (Severity) { + Severity["Critical"] = "critical"; + Severity["Error"] = "error"; + Severity["Warning"] = "warning"; + Severity["Info"] = "info"; +})(Severity || (Severity = {})); +class PagerDutyForm { + constructor(service_key, deduplication_id_column, schedule_id, auto_resolution_boolean, max_incidents, summary, severity, message) { + this.service_key = service_key; + this.deduplication_id_column = deduplication_id_column; + this.schedule_id = schedule_id; + this.auto_resolution_boolean = auto_resolution_boolean; + this.max_incidents = max_incidents; + this.summary = summary; + this.severity = severity; + this.message = message; + } + static jsonToInterface(json) { + return { + [FormFields.ServiceKeyKey]: json[FormFields.ServiceKeyKey], + [FormFields.DeDeuplicationIdColumnKey]: json[FormFields.DeDeuplicationIdColumnKey], + [FormFields.ScheduleIdKey]: json[FormFields.ScheduleIdKey], + [FormFields.AutoResolveKey]: Boolean(json[FormFields.AutoResolveKey]), + [FormFields.MaxIncidentsKey]: Number(json[FormFields.MaxIncidentsKey]), + [FormFields.Summary]: json[FormFields.Summary], + [FormFields.Severity]: Severity[json[FormFields.Severity]], + [FormFields.Message]: json[FormFields.Message] + }; + } + static create(json) { + const inter = this.jsonToInterface(json); + return new PagerDutyForm(inter[FormFields.ServiceKeyKey], inter[FormFields.DeDeuplicationIdColumnKey], inter[FormFields.ScheduleIdKey], inter[FormFields.AutoResolveKey], inter[FormFields.MaxIncidentsKey], inter[FormFields.Summary], inter[FormFields.Severity], inter[FormFields.Message]); + } + createPagerDutyIncidents(resultSet, plan) { + const details = { + title: plan.title, + type: plan.type, + model: plan.query.model, + url: plan.query.share_url, + }; + return resultSet.reduce((acc, el) => { + if (!Array.isArray(acc)) + return acc; + if (el[this.deduplication_id_column] == null) + return { + field: FormFields.DeDeuplicationIdColumnKey, + message: `Couldn't find column ${this.deduplication_id_column} in result set` + }; + const templatedMessage = Mustache.render(this.message, el); + const templatedSummary = Mustache.render(this.summary, el); + const incident = { + routing_key: this.service_key, + event_action: pagerduty_create_incident_1.PagerDutyEventAction.Trigger, + dedup_key: el[this.deduplication_id_column], + payload: { + summary: templatedSummary, + severity: this.severity, + source: plan.query.url, + timestamp: moment().format(), + custom_details: Object.assign(Object.assign(Object.assign({ managed_by_looker: true, auto_resolve: this.auto_resolution_boolean, schedule_id: this.schedule_id }, details), el), { message: templatedMessage }) + }, + client: "Looker", + client_url: details.url, + links: [{ href: details.url, text: 'Scheduled query' }], + }; + return acc.concat([incident]); + }, []); + } +} +exports.PagerDutyForm = PagerDutyForm; +PagerDutyForm.formFields = [ + { + label: 'Service key', + type: 'string', + name: FormFields.ServiceKeyKey, + description: 'An Events API v2 integration key', + required: true + }, { + label: 'De-duplication id column', + name: FormFields.DeDeuplicationIdColumnKey, + description: 'Column in the result set that uniquely identifies an alert', + type: 'string', + required: true + }, { + label: 'Unique name or ID of this schedule', + name: FormFields.ScheduleIdKey, + description: 'A value that uniquely identifies this schedule. Used to ensure schedules do not incorrectly resolve alerts generated by other schedules.', + type: 'string', + required: true + }, { + label: 'Enable automatic resolution', + name: FormFields.AutoResolveKey, + description: 'Automatically resolves incidents', + type: 'string', + default: 'true', + required: true + }, + { + label: 'Maximum number of incidents', + name: FormFields.MaxIncidentsKey, + description: 'Maximum number of incidents to create based on result set', + type: 'string', + default: '10', + required: true + }, + { + label: 'Summary', + name: FormFields.Summary, + description: 'Incident summary', + type: 'string', + required: true + }, + { + label: 'Severity', + name: FormFields.Severity, + description: 'Severity', + type: 'select', + default: "Critical", + options: Object.keys(Severity).map(k => ({ name: k, label: k })), + required: true + }, + { + label: 'Message', + name: FormFields.Message, + description: 'Message', + type: 'textarea', + required: true + }, +]; diff --git a/lib/actions/pagerduty/pagerduty_incident.d.ts b/lib/actions/pagerduty/pagerduty_incident.d.ts new file mode 100644 index 000000000..1e8806836 --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_incident.d.ts @@ -0,0 +1,16 @@ +import { CustomDetails } from './pagerduty_create_incident'; +/** + * API Reference + * + * https://developer.pagerduty.com/api-reference/reference/REST/openapiv3.json/paths/~1incidents/get + */ +export interface PagerDutyIncident { + id: string; +} +export interface PagerDutyAlert { + id: string; + alert_key: string; + body?: { + details?: CustomDetails; + }; +} diff --git a/lib/actions/pagerduty/pagerduty_incident.js b/lib/actions/pagerduty/pagerduty_incident.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/actions/pagerduty/pagerduty_incident.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/actions/pagerduty/service.d.ts b/lib/actions/pagerduty/service.d.ts new file mode 100644 index 000000000..91b4f24dd --- /dev/null +++ b/lib/actions/pagerduty/service.d.ts @@ -0,0 +1,14 @@ +/** + * API Reference: + * + * https://developer.pagerduty.com/api-reference/reference/REST/openapiv3.json/paths/~1services/get + */ +export interface Integration { + integration_key: string; +} +export interface Service { + id: string; + name: string; + description: string; + integrations: Integration[]; +} diff --git a/lib/actions/pagerduty/service.js b/lib/actions/pagerduty/service.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/actions/pagerduty/service.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/actions/salesforce/common/oauth_helper.js b/lib/actions/salesforce/common/oauth_helper.js index 238a7fdf8..61d35347a 100644 --- a/lib/actions/salesforce/common/oauth_helper.js +++ b/lib/actions/salesforce/common/oauth_helper.js @@ -16,6 +16,7 @@ const querystring = require("querystring"); const winston = require("winston"); const Hub = require("../../../hub"); const salesforce_campaigns_1 = require("../campaigns/salesforce_campaigns"); +const url_1 = require("url"); class SalesforceOauthHelper { constructor(oauthClientId, oauthClientSecret) { this.oauthCreds = { oauthClientId, oauthClientSecret }; @@ -74,7 +75,7 @@ class SalesforceOauthHelper { }); const payload = JSON.parse(plaintext); const authorizeUrl = `${payload.salesforce_domain}/services/oauth2/authorize`; - const url = new URL(authorizeUrl); + const url = new url_1.URL(authorizeUrl); url.search = querystring.stringify({ response_type: "code", client_id: payload.salesforceClientId, diff --git a/package.json b/package.json index 4dd850579..9ec959bdf 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,6 @@ "typescript": "^3.9.7", "uuid": "^3.4.0", "winston": "^2.4.5", - "firebase-admin": "^10.0.0", "yarn": "^1.22.18" }, "typings": "lib/index", diff --git a/src/actions/firebase/firebase.png b/src/actions/firebase/firebase.png deleted file mode 100644 index 012670e5f..000000000 Binary files a/src/actions/firebase/firebase.png and /dev/null differ diff --git a/src/actions/firebase/firebase.ts b/src/actions/firebase/firebase.ts deleted file mode 100644 index f84c4638b..000000000 --- a/src/actions/firebase/firebase.ts +++ /dev/null @@ -1,156 +0,0 @@ -import * as firebaseAdmin from "firebase-admin" -import * as firebaseApp from "firebase-admin/app" -import { v4 } from "uuid" -import * as winston from "winston" -import * as Hub from "../../hub" - -const LOG_PREFIX = "[Firebase]" - -export class FirebaseAction extends Hub.Action { - static firebaseAdmin: firebaseApp.App - - static setFirebaseClient() { - if (firebaseAdmin.apps.length === 0) { - FirebaseAction.firebaseAdmin = firebaseAdmin.initializeApp({ - credential: firebaseAdmin.credential.cert({ - projectId: process.env.FIREBASE_PROJECT_ID, - clientEmail: process.env.FIREBASE_CLIENT_EMAIL, - privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n"), - }), - databaseURL: process.env.FIREBASE_DATABASE, - }) - } - } - - name = "firebase" - label = "Firebase" - iconName = "firebase/firebase.png" - description = "Use firebase to send push notifications to mobile." - minimumSupportedLookerVersion = "22.3.0" - contentType = "image/jpeg" - notificationOptions = { - priority: "high", - timeToLive: 60 * 60 * 24, - contentAvailable: true, - mutableContent: true, - } - params = [] - supportedActionTypes = [Hub.ActionType.Query] - supportedFormats = [Hub.ActionFormat.JsonDetail] - supportedFormattings = [Hub.ActionFormatting.Unformatted] - supportedVisualizationFormattings = [Hub.ActionVisualizationFormatting.Noapply] - - async execute(request: Hub.ActionRequest) { - const response = new Hub.ActionResponse({success: true}) - const webhookId = request.webhookId - winston.info(`${LOG_PREFIX} Firebase action (v 16.06.2022) called.`, { webhookId }) - let data: any = {} - if (request.formParams.data) { - data = request.formParams.data - if (!data.alert_id) { - winston.warn(`${LOG_PREFIX} Need Valid AlertId.`, { webhookId }) - throw "Need Valid AlertId." - } - } else { - winston.warn(`${LOG_PREFIX} Need valid notification data.`, { webhookId }) - throw "Need valid notification data." - } - await this.verifyAndSendMessage(request.formParams, webhookId) - return new Hub.ActionResponse(response) - } - - async verifyAndSendMessage(params: Hub.ParamMap, webhookId: string | undefined): Promise { - return new Promise(async (resolve, reject) => { - const data: any = params.data - if (!params.title) { - winston.warn(`${LOG_PREFIX} Needs a valid title.`, { webhookId }) - reject("Needs a valid title.") - } - if (!params.deviceIds) { - winston.warn(`${LOG_PREFIX} Device Ids not present.`, { webhookId }) - resolve() - } - const notification: any = { - title: params.title, - body : `On ${data.dashboard_name}`, - } - const notificationData: any = data - const notificationOptions = this.notificationOptions - notificationData.id = v4() - if (params.timeToLive) { - notificationOptions.timeToLive = parseFloat(params.timeToLive) - } - if (params.priority) { - notificationOptions.priority = params.priority - } - try { - const userObj = JSON.parse(params.deviceIds ?? "[]") as any[] - const deviceIdObject = params.deviceIds as unknown as any[] - if (deviceIdObject.length === 0) { - winston.warn(`${LOG_PREFIX} Device Id length is 0.`, { webhookId }) - resolve() - } - for (const userDevices of userObj) { - const devices = userDevices as any[] - for (const device of devices) { - if (device.device_id && device.user_id) { - const deviceId = device.device_id.toString() - notificationData.user_id = device.user_id.toString() - const payload = { - notification, - data: notificationData, - } - try { - await this.sendMessageToDevice(deviceId, webhookId, payload, notificationOptions) - } catch (error) { - winston.error(`${LOG_PREFIX} Error in sendMessageToDevice. ${error.toString()} `, { webhookId }) - reject(error) - } - } - } - } - } catch (error) { - winston.error(`${LOG_PREFIX} Error. ${error.toString()} `, { webhookId }) - reject(error) - } - resolve() - }) - .catch((error: any) => { - winston.error(`${LOG_PREFIX} Error. ${error.toString()} `, { webhookId }) - throw error - }) - } - - async sendMessageToDevice(deviceId: string, - webhookId: string | undefined, - payload: firebaseAdmin.messaging.MessagingPayload, - options?: firebaseAdmin.messaging.MessagingOptions, - ): Promise { - return new Promise((resolve, reject) => { - FirebaseAction.setFirebaseClient() - firebaseAdmin.messaging().sendToDevice(deviceId, payload, options) - .then( (response: any) => { - winston.info(`${LOG_PREFIX} notification sent to firebase. ${JSON.stringify(response)}`, { webhookId }) - resolve() - }) - .catch( (error: any) => { - winston.error(`${LOG_PREFIX} notification sending failed to firebase. ${error.toString()} `, { webhookId }) - reject(error.message) - }) - }) - .catch((error) => { - throw error - }) - } -} - -if (process.env.FIREBASE_PROJECT_ID - && process.env.FIREBASE_CLIENT_EMAIL - && process.env.FIREBASE_PRIVATE_KEY - && process.env.FIREBASE_DATABASE - ) { - Hub.addAction(new FirebaseAction()) - winston.warn(`${LOG_PREFIX} Action registered.`) -} else { - winston.warn(`${LOG_PREFIX} Action not registered because required environment variables are missing.`) -} diff --git a/src/actions/firebase/test_firebase.ts b/src/actions/firebase/test_firebase.ts deleted file mode 100644 index e777b035c..000000000 --- a/src/actions/firebase/test_firebase.ts +++ /dev/null @@ -1,89 +0,0 @@ -import * as chai from "chai" -import * as sinon from "sinon" - -import * as Hub from "../../hub" - -import { FirebaseAction } from "./firebase" - -const action = new FirebaseAction() - -function expectFirebaseMatch(request: Hub.ActionRequest, sendMessageMatch: any) { - const spySendMessage = sinon.spy(async () => Promise.resolve()) - - const stubClientSendMessage = sinon.stub(action as any, "verifyAndSendMessage") - .callsFake(spySendMessage) - - return chai.expect(action.execute(request)).to.be.fulfilled.then(() => { - chai.expect(stubClientSendMessage).to.have.been.calledWithMatch(sendMessageMatch) - stubClientSendMessage.restore() - }) -} - -describe(`${action.constructor.name} unit tests`, () => { - - describe("action", () => { - it("errors if there is no notification data", () => { - const request = new Hub.ActionRequest() - request.formParams = {} - request.attachment = {} - request.attachment.dataBuffer = Buffer.from("1,2,3,4", "utf8") - - return chai.expect(action.execute(request)).to.eventually - .be.rejectedWith("Need valid notification data.") - }) - - it("errors if there is no alertId.", () => { - const request = new Hub.ActionRequest() - const dashboardData = {dashboard_id: "123"} - request.formParams = {title: "title", data: JSON.stringify(dashboardData)} - request.attachment = {} - request.attachment.dataBuffer = Buffer.from("1,2,3,4", "utf8") - - return chai.expect(action.execute(request)).to.eventually - .be.rejectedWith("Need Valid AlertId.") - }) - - it("errors if there is no valid title.", () => { - const request = new Hub.ActionRequest() - const alertIdData = {alert_id: "123"} - request.formParams = {data: alertIdData as any} - request.attachment = {} - request.attachment.dataBuffer = Buffer.from("1,2,3,4", "utf8") - - return chai.expect(action.execute(request)).to.eventually - .be.rejectedWith("Needs a valid title.") - }) - - it("no errors if there is valid request", () => { - const response = new Hub.ActionResponse({success: true}) - const request = new Hub.ActionRequest() - const alertIdData = {alert_id: "123"} - request.formParams = {title: "title", data: alertIdData as any} - request.attachment = {} - request.attachment.dataBuffer = Buffer.from("1,2,3,4", "utf8") - - return chai.expect(action.execute(request)).to.eventually - .deep.equal(response) - }) - - it("no errors if there is valid deviceId's", () => { - const request = new Hub.ActionRequest() - const alertIdData = {alert_id: "123"} - const deviceIdData = {deviceIds: [{userId: "1", deviceId: "1"}, {userId: "1", deviceId: "1"}]} - request.formParams = {title: "title", data: alertIdData as any, deviceIds: deviceIdData as any} - request.attachment = {} - request.attachment.dataBuffer = Buffer.from("1,2,3,4", "utf8") - - return expectFirebaseMatch(request, request.formParams) - }) - - it("Check right methods being called", () => { - const request = new Hub.ActionRequest() - const alertIdData = {alert_id: "123"} - request.formParams = {title: "title", data: alertIdData as any} - request.attachment = {} - request.attachment.dataBuffer = Buffer.from("1,2,3,4", "utf8") - return expectFirebaseMatch(request, request.formParams) - }) - }) -}) diff --git a/src/actions/index.ts b/src/actions/index.ts index face54461..f312b8c6d 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -9,7 +9,6 @@ import "./digitalocean/digitalocean_droplet" import "./digitalocean/digitalocean_object_storage" import "./dropbox/dropbox" import "./facebook/facebook_custom_audiences" -import "./firebase/firebase" import "./google/ads/customer_match" import "./google/analytics/data_import" import "./google/drive/google_drive" diff --git a/yarn.lock b/yarn.lock index fb0a66aa5..f0af9b9fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -51,70 +51,6 @@ enabled "2.0.x" kuler "^2.0.0" -"@firebase/app-types@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.7.0.tgz#c9e16d1b8bed1a991840b8d2a725fb58d0b5899f" - integrity sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg== - -"@firebase/auth-interop-types@0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz#5ce13fc1c527ad36f1bb1322c4492680a6cf4964" - integrity sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g== - -"@firebase/component@0.5.11": - version "0.5.11" - resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.5.11.tgz#af00aacf3a8348d159b1fd9a91945e1b15b03aaf" - integrity sha512-amtUrJxfJhJdjR3JzXqkHIoghJJ34o8OiSDj3gq96uKL4BRkSpmPaxi0+1r8DcDQ6bQxh3kDSoge8bRCDQCvsw== - dependencies: - "@firebase/util" "1.5.0" - tslib "^2.1.0" - -"@firebase/database-compat@^0.1.1": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.1.6.tgz#eeff5de0ea4b146803e37c395cfdcbe8c9802b48" - integrity sha512-fDAJWI5ZdXPlS84NC87Et7pE6mJxF5uUoePCaQFpU56wrYVk58COomcSXtFrdX9U5/1FHjR3TaDWV5pJakv83g== - dependencies: - "@firebase/component" "0.5.11" - "@firebase/database" "0.12.6" - "@firebase/database-types" "0.9.5" - "@firebase/logger" "0.3.2" - "@firebase/util" "1.5.0" - tslib "^2.1.0" - -"@firebase/database-types@0.9.5", "@firebase/database-types@^0.9.3": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.9.5.tgz#b5788440b1c77e6e9d9cafa74ea19f44f5b71de9" - integrity sha512-0p9BDmoZCbW5c//tl7IUn8hOIM4M6wCnLmVdbVUvD30V4hZT36phdhajf36pcMgE9suMsz4xtvWlngEy9FeHwA== - dependencies: - "@firebase/app-types" "0.7.0" - "@firebase/util" "1.5.0" - -"@firebase/database@0.12.6": - version "0.12.6" - resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.12.6.tgz#d7ee5b8728b1d46b0ee88cf713642ebae5b1d9fc" - integrity sha512-vokGkgpk+4bvy1d/s0lsPP9GmC1nrAtctQwEEDH5ZO4WCYPj16Y6rKILsOjrWwJ+Ih21ORnekxSzfpKyd1KHEg== - dependencies: - "@firebase/auth-interop-types" "0.1.6" - "@firebase/component" "0.5.11" - "@firebase/logger" "0.3.2" - "@firebase/util" "1.5.0" - faye-websocket "0.11.4" - tslib "^2.1.0" - -"@firebase/logger@0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.3.2.tgz#5046ffa8295c577846d54b6ca95645a03809800e" - integrity sha512-lzLrcJp9QBWpo40OcOM9B8QEtBw2Fk1zOZQdvv+rWS6gKmhQBCEMc4SMABQfWdjsylBcDfniD1Q+fUX1dcBTXA== - dependencies: - tslib "^2.1.0" - -"@firebase/util@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.5.0.tgz#0b6f5eaef49e57896fe152973bbc64f8af172123" - integrity sha512-4w4OY3YJVHV/4UBZ8OcXb8BD8I83P5n2y+FW0dHhn9OLXdYDg8bvCTA08P0nszpZqBhwutKQ4OS7c530SGjeLg== - dependencies: - tslib "^2.1.0" - "@google-cloud/common@^0.17.0": version "0.17.0" resolved "https://registry.yarnpkg.com/@google-cloud/common/-/common-0.17.0.tgz#8ef558750db481fc10a13757a49479ab9a1c8c07" @@ -139,49 +75,6 @@ string-format-obj "^1.1.0" through2 "^2.0.3" -"@google-cloud/common@^3.8.1": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@google-cloud/common/-/common-3.10.0.tgz#454d1155bb512109cd83c6183aabbd39f9aabda7" - integrity sha512-XMbJYMh/ZSaZnbnrrOFfR/oQrb0SxG4qh6hDisWCoEbFcBHV0qHQo4uXfeMCzolx2Mfkh6VDaOGg+hyJsmxrlw== - dependencies: - "@google-cloud/projectify" "^2.0.0" - "@google-cloud/promisify" "^2.0.0" - arrify "^2.0.1" - duplexify "^4.1.1" - ent "^2.2.0" - extend "^3.0.2" - google-auth-library "^7.14.0" - retry-request "^4.2.2" - teeny-request "^7.0.0" - -"@google-cloud/firestore@^4.5.0": - version "4.15.1" - resolved "https://registry.yarnpkg.com/@google-cloud/firestore/-/firestore-4.15.1.tgz#ed764fc76823ce120e68fe8c27ef1edd0650cd93" - integrity sha512-2PWsCkEF1W02QbghSeRsNdYKN1qavrHBP3m72gPDMHQSYrGULOaTi7fSJquQmAtc4iPVB2/x6h80rdLHTATQtA== - dependencies: - fast-deep-equal "^3.1.1" - functional-red-black-tree "^1.0.1" - google-gax "^2.24.1" - protobufjs "^6.8.6" - -"@google-cloud/paginator@^3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@google-cloud/paginator/-/paginator-3.0.7.tgz#fb6f8e24ec841f99defaebf62c75c2e744dd419b" - integrity sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ== - dependencies: - arrify "^2.0.0" - extend "^3.0.2" - -"@google-cloud/projectify@^2.0.0": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@google-cloud/projectify/-/projectify-2.1.1.tgz#ae6af4fee02d78d044ae434699a630f8df0084ef" - integrity sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ== - -"@google-cloud/promisify@^2.0.0": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@google-cloud/promisify/-/promisify-2.0.4.tgz#9d8705ecb2baa41b6b2673f3a8e9b7b7e1abc52a" - integrity sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA== - "@google-cloud/storage@^1.5.2": version "1.7.0" resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-1.7.0.tgz#07bff573d92d5c294db6a04af246688875a8f74b" @@ -209,53 +102,6 @@ through2 "^2.0.0" xdg-basedir "^3.0.0" -"@google-cloud/storage@^5.3.0": - version "5.18.2" - resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-5.18.2.tgz#0ded98a69323d253e6dd986650edc89b5c504bf9" - integrity sha512-hL/6epBF2uPt7YtJoOKI6mVxe6RsKBs7S8o2grE0bFGdQKSOngVHBcstH8jDw7aN2rXGouA2TfVTxH+VapY5cg== - dependencies: - "@google-cloud/common" "^3.8.1" - "@google-cloud/paginator" "^3.0.7" - "@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" - extend "^3.0.2" - gaxios "^4.0.0" - get-stream "^6.0.0" - google-auth-library "^7.0.0" - hash-stream-validation "^0.2.2" - mime "^3.0.0" - mime-types "^2.0.8" - p-limit "^3.0.1" - pumpify "^2.0.0" - snakeize "^0.1.0" - stream-events "^1.0.4" - xdg-basedir "^4.0.0" - -"@grpc/grpc-js@~1.5.0": - version "1.5.9" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.5.9.tgz#df44b3d6bc1d5eb4779aab96e00f6084fd07a3c8" - integrity sha512-un+cXqErq5P4p3+WgYVNVh7FB51MSnaoRef7QWDcMXKR6FX2R6Z/bltcJMxNNdTUMC85lkOQcpnAAetFziPSng== - dependencies: - "@grpc/proto-loader" "^0.6.4" - "@types/node" ">=12.12.47" - -"@grpc/proto-loader@^0.6.1", "@grpc/proto-loader@^0.6.4": - version "0.6.9" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.9.tgz#4014eef366da733f8e04a9ddd7376fe8a58547b7" - integrity sha512-UlcCS8VbsU9d3XTXGiEVFonN7hXk+oMXZtoHHG2oSA1/GcDP1q6OUgs20PzHDGizzyi8ufGSUDlk3O2NyY7leg== - dependencies: - "@types/long" "^4.0.1" - lodash.camelcase "^4.3.0" - long "^4.0.0" - protobufjs "^6.10.0" - yargs "^16.2.0" - "@hubspot/api-client@^2.0.1": version "2.1.1" resolved "https://registry.yarnpkg.com/@hubspot/api-client/-/api-client-2.1.1.tgz#79253b149cb44208faa617bc02e09d9f445d54e0" @@ -270,64 +116,6 @@ lodash "^4.17.19" request "^2.88.0" -"@panva/asn1.js@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6" - integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw== - -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= - "@segment/loosely-validate-event@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz#87dfc979e5b4e7b82c5f1d8b722dfd5d77644681" @@ -493,11 +281,6 @@ dependencies: defer-to-connect "^2.0.0" -"@tootallnate/once@2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" - integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== - "@types/base64-url@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@types/base64-url/-/base64-url-2.2.0.tgz#ff17c19bf357821bd637af2f54f7922443377950" @@ -578,14 +361,6 @@ dependencies: "@types/node" "*" -"@types/express-jwt@0.0.42": - version "0.0.42" - resolved "https://registry.yarnpkg.com/@types/express-jwt/-/express-jwt-0.0.42.tgz#4f04e1fadf9d18725950dc041808a4a4adf7f5ae" - integrity sha512-WszgUddvM1t5dPpJ3LhWNH8kfNN8GPIBrAGxgIYXVCEGx6Bx4A036aAuf/r5WH9DIEdlmp7gHOYvSM6U87B0ag== - dependencies: - "@types/express" "*" - "@types/express-unless" "*" - "@types/express-serve-static-core@^4.17.18": version "4.17.28" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz#c47def9f34ec81dc6328d0b1b5303d1ec98d86b8" @@ -595,13 +370,6 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express-unless@*": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@types/express-unless/-/express-unless-0.5.3.tgz#271f8603617445568ed0d6efe25a7d2f338544c1" - integrity sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw== - dependencies: - "@types/express" "*" - "@types/express@*", "@types/express@^4.17.7": version "4.17.13" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" @@ -643,11 +411,6 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== -"@types/long@^4.0.0", "@types/long@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" - integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== - "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -668,11 +431,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.10.tgz#616f16e9d3a2a3d618136b1be244315d95bd7cab" integrity sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog== -"@types/node@>=12.12.47", "@types/node@>=13.7.0": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== - "@types/node@>=8.0.0 <15": version "14.18.23" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.23.tgz#70f5f20b0b1b38f696848c1d3647bb95694e615e" @@ -1098,7 +856,7 @@ arrify@^1.0.0, arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -arrify@^2.0.0, arrify@^2.0.1: +arrify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== @@ -1152,13 +910,6 @@ async-mutex@^0.1.4: resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.1.4.tgz#a47d1eebf584f7dcdd760e3642dc2c58613bef5c" integrity sha512-zVWTmAnxxHaeB2B1te84oecI8zTDJ/8G49aVBblRX6be0oq6pAybNcUSxwfgVOmOjSCvN4aYZAqwtyNI8e1YGw== -async-retry@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" - integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== - dependencies: - retry "0.13.1" - async@^2.0.1, async@^2.3.0, async@^2.4.0: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" @@ -1894,18 +1645,6 @@ configstore@^3.0.0, configstore@^3.1.2: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" -configstore@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" - integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== - 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" - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -1992,11 +1731,6 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= -crypto-random-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" - integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== - csprng@*: version "0.1.2" resolved "https://registry.yarnpkg.com/csprng/-/csprng-0.1.2.tgz#4bc68f12fa368d252a59841cbaca974b18ab45e2" @@ -2042,11 +1776,6 @@ datauri@^1.0.5: mimer "^0.3.2" semver "^5.5.0" -date-and-time@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/date-and-time/-/date-and-time-2.3.0.tgz#1b509be4c938dbbf5fc9c14d66e1daf9fe3cef13" - integrity sha512-DY53oj742mykXjZzDxT7NxH5cxwBRb7FsVG5+8pcV96qU9JQd0UhA21pQB18fwwsXOXeSM0RJV4OzgVxu8eatg== - dayjs@^1.8.29: version "1.10.7" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" @@ -2087,13 +1816,6 @@ debug@^3.1.0, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.3.2: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2235,13 +1957,6 @@ diacritics@1.3.0: resolved "https://registry.yarnpkg.com/diacritics/-/diacritics-1.3.0.tgz#3efa87323ebb863e6696cebb0082d48ff3d6f7a1" integrity sha1-PvqHMj67hj5mls67AILUj/PW96E= -dicer@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.1.tgz#abf28921e3475bc5e801e74e0159fd94f927ba97" - integrity sha512-ObioMtXnmjYs3aRtpIJt9rgQSPCIhKVkFPip+E9GUDyWl8N435znUxK/JfNwGZJ2wnn5JKQ7Ly3vOK5Q5dylGA== - dependencies: - streamsearch "^1.1.0" - diff@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" @@ -2271,13 +1986,6 @@ dot-prop@^4.2.1: dependencies: is-obj "^1.0.0" -dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - dotenv@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" @@ -2313,16 +2021,6 @@ duplexify@^3.5.0, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" -duplexify@^4.0.0, duplexify@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" - integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== - dependencies: - end-of-stream "^1.4.1" - inherits "^2.0.3" - readable-stream "^3.1.1" - stream-shift "^1.0.0" - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -2358,7 +2056,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: +end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -2613,12 +2311,12 @@ fast-safe-stringify@^2.0.7: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== -fast-text-encoding@^1.0.0, fast-text-encoding@^1.0.3: +fast-text-encoding@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz#ec02ac8e01ab8a319af182dae2681213cfe9ce53" integrity sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig== -faye-websocket@0.11.4, faye-websocket@>=0.9.1: +faye-websocket@>=0.9.1: version "0.11.4" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== @@ -2697,22 +2395,6 @@ finity@^0.5.4: resolved "https://registry.yarnpkg.com/finity/-/finity-0.5.4.tgz#f2a8a9198e8286467328ec32c8bfcc19a2229c11" integrity sha512-3l+5/1tuw616Lgb0QBimxfdd2TqaDGpfCBpfX6EqtFmqUV3FtQnVEX4Aa62DagYEqnsTIjZcTfbq9msDbXYgyA== -firebase-admin@^10.0.0: - version "10.0.2" - resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-10.0.2.tgz#d1142fb40738fa9b62f6625c4e3fc8cbc0ba61c6" - integrity sha512-MLH0SPmC4L0aCHvPjs1KThraru/T84T3hxiPY3uCH7NZEgE/T5n4GwecwU3RcM3X+br75BIBY7qhaR5uCxhdXA== - 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.0.0" - optionalDependencies: - "@google-cloud/firestore" "^4.5.0" - "@google-cloud/storage" "^5.3.0" - flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" @@ -2827,11 +2509,6 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - gaxios@^4.0.0: version "4.3.3" resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-4.3.3.tgz#d44bdefe52d34b6435cc41214fdb160b64abfc22" @@ -2907,11 +2584,6 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - get-uri@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.4.tgz#d4937ab819e218d4cb5ae18e4f5962bef169cc6a" @@ -2998,7 +2670,7 @@ globals@^9.18.0: resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== -google-auth-library@^1.3.1, google-auth-library@^6.0.0, google-auth-library@^7.0.0, google-auth-library@^7.14.0: +google-auth-library@^1.3.1, google-auth-library@^6.0.0, google-auth-library@^7.14.0: version "7.14.1" resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-7.14.1.tgz#e3483034162f24cc71b95c8a55a210008826213c" integrity sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA== @@ -3023,25 +2695,6 @@ google-auto-auth@^0.10.0: google-auth-library "^1.3.1" request "^2.79.0" -google-gax@^2.24.1: - version "2.30.1" - resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-2.30.1.tgz#57a2826d53837bc74b071c3d27355c7bed5a9939" - integrity sha512-AR00wrunctUqwKQFl15Yq5bo9NuFLnT0zguZYCf8eAqoOUMbxn9V1L0ONCtV4+P9z7sLu+cjtgl+5b4eRZvktg== - dependencies: - "@grpc/grpc-js" "~1.5.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" - google-p12-pem@^3.1.3: version "3.1.4" resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.1.4.tgz#123f7b40da204de4ed1fbf2fd5be12c047fc8b3b" @@ -3209,7 +2862,7 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" -hash-stream-validation@^0.2.1, hash-stream-validation@^0.2.2: +hash-stream-validation@^0.2.1: version "0.2.4" resolved "https://registry.yarnpkg.com/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz#ee68b41bf822f7f44db1142ec28ba9ee7ccb7512" integrity sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ== @@ -3282,15 +2935,6 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" - integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== - dependencies: - "@tootallnate/once" "2" - agent-base "6" - debug "4" - http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -3592,11 +3236,6 @@ is-obj@^1.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - is-path-inside@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" @@ -3631,7 +3270,7 @@ is-retry-allowed@^2.2.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== -is-stream-ended@^0.1.0, is-stream-ended@^0.1.4: +is-stream-ended@^0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/is-stream-ended/-/is-stream-ended-0.1.4.tgz#f50224e95e06bce0e356d440a4827cd35b267eda" integrity sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw== @@ -3646,7 +3285,7 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= @@ -3717,13 +3356,6 @@ join-component@^1.1.0: resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5" integrity sha1-uEF7dQZho5K+4sJTfGiyqdSXfNU= -jose@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/jose/-/jose-2.0.5.tgz#29746a18d9fff7dcf9d5d2a6f62cb0c7cd27abd3" - integrity sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA== - dependencies: - "@panva/asn1.js" "^1.0.0" - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -3863,17 +3495,6 @@ jwa@^2.0.0: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jwks-rsa@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/jwks-rsa/-/jwks-rsa-2.0.5.tgz#5dc911cdade803a149b7d4d41404a7c1bf2c221a" - integrity sha512-fliHfsiBRzEU0nXzSvwnh0hynzGB0WihF+CinKbSRlaqRxbqqKf2xbBPgwc8mzf18/WgwlG8e5eTpfSTBcU4DQ== - dependencies: - "@types/express-jwt" "0.0.42" - debug "^4.3.2" - jose "^2.0.5" - limiter "^1.1.5" - lru-memoizer "^2.1.4" - jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" @@ -3953,11 +3574,6 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -limiter@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2" - integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA== - load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -3983,16 +3599,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - lodash.get@^4.4.2, lodash.get@~4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -4073,11 +3679,6 @@ lolex@^5.0.1: dependencies: "@sinonjs/commons" "^1.7.0" -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -4110,22 +3711,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" - integrity sha1-HRdnnAac2l0ECZGgnbwsDbN35V4= - dependencies: - pseudomap "^1.0.1" - yallist "^2.0.0" - -lru-memoizer@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.1.4.tgz#b864d92b557f00b1eeb322156a0409cb06dafac6" - integrity sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ== - dependencies: - lodash.clonedeep "^4.5.0" - lru-cache "~4.0.0" - mailchimp@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/mailchimp/-/mailchimp-1.2.1.tgz#d1fc4ba4ca81d868228e2050be511c00b64b3cac" @@ -4141,13 +3726,6 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -4260,7 +3838,7 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@>=2.0.3, mime@^3.0.0: +mime@>=2.0.3: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== @@ -4470,14 +4048,14 @@ nise@^1.3.3: lolex "^5.0.1" path-to-regexp "^1.7.0" -node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -node-forge@^1.0.0, node-forge@^1.3.1: +node-forge@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== @@ -4580,11 +4158,6 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-hash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" - integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== - object-inspect@^1.9.0: version "1.12.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" @@ -4692,7 +4265,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^3.0.1, p-limit@^3.0.2: +p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -4924,32 +4497,6 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -proto3-json-serializer@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/proto3-json-serializer/-/proto3-json-serializer-0.1.8.tgz#f80f9afc1efe5ed9a9856bbbd17dc7cabd7ce9a3" - integrity sha512-ACilkB6s1U1gWnl5jtICpnDai4VCxmI9GFxuEaYdxtDG2oVI3sVFIUsvUZcQbJgtPM6p+zqKbjTKQZp6Y4FpQw== - dependencies: - protobufjs "^6.11.2" - -protobufjs@6.11.2, protobufjs@^6.10.0, protobufjs@^6.11.2, protobufjs@^6.8.6: - version "6.11.2" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b" - integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw== - 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" - proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -4977,7 +4524,7 @@ proxy-from-env@^1.0.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -pseudomap@^1.0.1, pseudomap@^1.0.2: +pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= @@ -5017,15 +4564,6 @@ pumpify@^1.4.0, pumpify@^1.5.1: inherits "^2.0.3" pump "^2.0.0" -pumpify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-2.0.1.tgz#abfc7b5a621307c728b551decbbefb51f0e4aa1e" - integrity sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw== - dependencies: - duplexify "^4.1.1" - inherits "^2.0.3" - pump "^3.0.0" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -5177,7 +4715,7 @@ readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stre string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.2, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -5380,24 +4918,16 @@ retry-request@^3.0.0: request "^2.81.0" through2 "^2.0.0" -retry-request@^4.0.0, retry-request@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-4.2.2.tgz#b7d82210b6d2651ed249ba3497f07ea602f1a903" - integrity sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg== - dependencies: - debug "^4.1.1" - extend "^3.0.2" - -retry@0.13.1, retry@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== - retry@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + rimraf@~2.4.0: version "2.4.5" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" @@ -5481,11 +5011,6 @@ semver-diff@^2.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - semver@^7.3.2: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" @@ -5823,7 +5348,7 @@ stream-combiner@~0.0.4: dependencies: duplexer "~0.1.1" -stream-events@^1.0.1, stream-events@^1.0.3, stream-events@^1.0.4, stream-events@^1.0.5: +stream-events@^1.0.1, stream-events@^1.0.3: version "1.0.5" resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== @@ -5835,11 +5360,6 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - string-format-obj@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/string-format-obj/-/string-format-obj-1.1.1.tgz#c7612ca4e2ad923812a81db192dc291850aa1f65" @@ -6030,17 +5550,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -teeny-request@^7.0.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-7.2.0.tgz#41347ece068f08d741e7b86df38a4498208b2633" - integrity sha512-SyY0pek1zWsi0LRVAALem+avzMLc33MKW/JLLakdP4s9+D7+jHcy5x6P+h94g2QNZsAqQNfX5lsbd3WSeJXrrw== - 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" - term-size@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" @@ -6173,7 +5682,7 @@ tslib@^1.8.0, tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.1, tslib@^2.1.0: +tslib@^2.0.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -6260,13 +5769,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -6304,13 +5806,6 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" -unique-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" - integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== - dependencies: - crypto-random-string "^2.0.0" - universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -6613,16 +6108,6 @@ write-file-atomic@^2.0.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - ws@^5.2.0: version "5.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" @@ -6635,11 +6120,6 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= -xdg-basedir@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" - integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== - xml2js@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.0.tgz#124fc4114b4129c810800ecb2ac86cf25462cb9a" @@ -6711,7 +6191,7 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^2.0.0, yallist@^2.1.2: +yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= @@ -6753,7 +6233,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0, yargs@^16.2.0: +yargs@16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==