diff --git a/README.md b/README.md index e8c6475d90..ae149f7347 100644 --- a/README.md +++ b/README.md @@ -135,13 +135,18 @@ You can learn more about the Budibase API at the following places: ## 🏁 Get started - - Deploy Budibase self-hosted in your existing infrastructure, using Docker, Kubernetes, and Digital Ocean. Or use Budibase Cloud if you don't need to self-host, and would like to get started quickly. ### [Get started with self-hosting Budibase](https://docs.budibase.com/docs/hosting-methods) +- [Docker - single ARM compatible image](https://docs.budibase.com/docs/docker) +- [Docker Compose](https://docs.budibase.com/docs/docker-compose) +- [Kubernetes](https://docs.budibase.com/docs/kubernetes-k8s) +- [Digital Ocean](https://docs.budibase.com/docs/digitalocean) +- [Portainer](https://docs.budibase.com/docs/portainer) + + ### [Get started with Budibase Cloud](https://budibase.com) diff --git a/charts/budibase/templates/app-service-deployment.yaml b/charts/budibase/templates/app-service-deployment.yaml index 7a2c483cc8..fd46e77647 100644 --- a/charts/budibase/templates/app-service-deployment.yaml +++ b/charts/budibase/templates/app-service-deployment.yaml @@ -151,6 +151,10 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{ if .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 6 }} + {{ end }} restartPolicy: Always serviceAccountName: "" status: {} diff --git a/charts/budibase/templates/minio-service-deployment.yaml b/charts/budibase/templates/minio-service-deployment.yaml index 901fb61ad9..103f9e3ed2 100644 --- a/charts/budibase/templates/minio-service-deployment.yaml +++ b/charts/budibase/templates/minio-service-deployment.yaml @@ -68,6 +68,10 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{ if .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 6 }} + {{ end }} restartPolicy: Always serviceAccountName: "" volumes: @@ -75,4 +79,4 @@ spec: persistentVolumeClaim: claimName: minio-data status: {} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/budibase/templates/proxy-service-deployment.yaml b/charts/budibase/templates/proxy-service-deployment.yaml index bd6a5e311f..505a46f1e8 100644 --- a/charts/budibase/templates/proxy-service-deployment.yaml +++ b/charts/budibase/templates/proxy-service-deployment.yaml @@ -40,6 +40,10 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{ if .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 6 }} + {{ end }} restartPolicy: Always serviceAccountName: "" volumes: diff --git a/charts/budibase/templates/redis-service-deployment.yaml b/charts/budibase/templates/redis-service-deployment.yaml index 0b6cb12562..6e09346cad 100644 --- a/charts/budibase/templates/redis-service-deployment.yaml +++ b/charts/budibase/templates/redis-service-deployment.yaml @@ -47,6 +47,10 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{ if .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 6 }} + {{ end }} restartPolicy: Always serviceAccountName: "" volumes: @@ -54,4 +58,4 @@ spec: persistentVolumeClaim: claimName: redis-data status: {} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/budibase/templates/worker-service-deployment.yaml b/charts/budibase/templates/worker-service-deployment.yaml index a7f05f3137..918dab427b 100644 --- a/charts/budibase/templates/worker-service-deployment.yaml +++ b/charts/budibase/templates/worker-service-deployment.yaml @@ -145,6 +145,10 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{ if .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.imagePullSecrets | nindent 6 }} + {{ end }} restartPolicy: Always serviceAccountName: "" status: {} diff --git a/hosting/docker-compose.dev.yaml b/hosting/docker-compose.dev.yaml index be0bc74a26..7322b0e8a9 100644 --- a/hosting/docker-compose.dev.yaml +++ b/hosting/docker-compose.dev.yaml @@ -11,10 +11,11 @@ services: - minio_data:/data ports: - "${MINIO_PORT}:9000" + - "9001:9001" environment: MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} - command: server /data + command: server /data --console-address ":9001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml index 57cbf33709..f669f9261d 100644 --- a/hosting/docker-compose.yaml +++ b/hosting/docker-compose.yaml @@ -63,7 +63,7 @@ services: MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} MINIO_BROWSER: "off" - command: server /data + command: server /data --console-address ":9001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s diff --git a/lerna.json b/lerna.json index 62e09cf209..c8f2b409df 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.1.31", + "version": "1.1.33-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index 0c7d3989a2..4c24e0025b 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "build": "lerna run build", "build:dev": "lerna run prebuild && tsc --build --watch --preserveWatchOutput", "release": "lerna publish ${RELEASE_VERSION_TYPE:-patch} --yes --force-publish && yarn release:pro", - "release:develop": "lerna publish prerelease --yes --force-publish --dist-tag develop && yarn release:pro:develop", + "release:develop": "lerna publish prerelease --yes --force-publish --dist-tag develop --exact && yarn release:pro:develop", "release:pro": "bash scripts/pro/release.sh", "release:pro:develop": "bash scripts/pro/release.sh develop", "restore": "yarn run clean && yarn run bootstrap && yarn run build", @@ -85,4 +85,4 @@ "install:pro": "bash scripts/pro/install.sh", "dep:clean": "yarn clean && yarn bootstrap" } -} +} \ No newline at end of file diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 1fca8c59c2..9657702909 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -20,7 +20,7 @@ "test:watch": "jest --watchAll" }, "dependencies": { - "@budibase/types": "^1.1.31", + "@budibase/types": "1.1.33-alpha.0", "@techpass/passport-openidconnect": "0.3.2", "aws-sdk": "2.1030.0", "bcrypt": "5.0.1", diff --git a/packages/backend-core/src/auth.js b/packages/backend-core/src/auth.js index b60144a0de..9ae29a3cbd 100644 --- a/packages/backend-core/src/auth.js +++ b/packages/backend-core/src/auth.js @@ -18,6 +18,8 @@ const { ssoCallbackUrl, csrf, internalApi, + adminOnly, + joiValidator, } = require("./middleware") const { invalidateUser } = require("./cache/user") @@ -173,4 +175,6 @@ module.exports = { refreshOAuthToken, updateUserOAuth, ssoCallbackUrl, + adminOnly, + joiValidator, } diff --git a/packages/backend-core/src/db/constants.ts b/packages/backend-core/src/db/constants.ts index 716762dd45..9c6be25424 100644 --- a/packages/backend-core/src/db/constants.ts +++ b/packages/backend-core/src/db/constants.ts @@ -11,6 +11,7 @@ export enum AutomationViewModes { } export enum ViewNames { + USER_BY_APP = "by_app", USER_BY_EMAIL = "by_email2", BY_API_KEY = "by_api_key", USER_BY_BUILDERS = "by_builders", @@ -28,6 +29,7 @@ export const DeprecatedViews = { export enum DocumentTypes { USER = "us", + GROUP = "gr", WORKSPACE = "workspace", CONFIG = "config", TEMPLATE = "template", diff --git a/packages/backend-core/src/db/conversions.js b/packages/backend-core/src/db/conversions.js index 455cc712d8..90c04e9251 100644 --- a/packages/backend-core/src/db/conversions.js +++ b/packages/backend-core/src/db/conversions.js @@ -50,3 +50,8 @@ exports.getProdAppID = appId => { const rest = split.join(APP_DEV_PREFIX) return `${APP_PREFIX}${rest}` } + +exports.extractAppUUID = id => { + const split = id?.split("_") || [] + return split.length ? split[split.length - 1] : null +} diff --git a/packages/backend-core/src/db/pouch.js b/packages/backend-core/src/db/pouch.js index 59b7ff8ae7..12d7d787e3 100644 --- a/packages/backend-core/src/db/pouch.js +++ b/packages/backend-core/src/db/pouch.js @@ -102,6 +102,13 @@ exports.getPouch = (opts = {}) => { } } + if (opts.onDisk) { + POUCH_DB_DEFAULTS = { + prefix: undefined, + adapter: "leveldb", + } + } + if (opts.replication) { const replicationStream = require("pouchdb-replication-stream") PouchDB.plugin(replicationStream.plugin) diff --git a/packages/backend-core/src/db/utils.ts b/packages/backend-core/src/db/utils.ts index ba3f1dd3e9..8ab6fa6e98 100644 --- a/packages/backend-core/src/db/utils.ts +++ b/packages/backend-core/src/db/utils.ts @@ -8,7 +8,7 @@ import { doWithDB, allDbs } from "./index" import { getCouchInfo } from "./pouch" import { getAppMetadata } from "../cache/appMetadata" import { checkSlashesInUrl } from "../helpers" -import { isDevApp, isDevAppID } from "./conversions" +import { isDevApp, isDevAppID, getProdAppID } from "./conversions" import { APP_PREFIX } from "./constants" import * as events from "../events" @@ -107,6 +107,15 @@ export function getGlobalUserParams(globalId: any, otherProps: any = {}) { } } +export function getUsersByAppParams(appId: any, otherProps: any = {}) { + const prodAppId = getProdAppID(appId) + return { + ...otherProps, + startkey: prodAppId, + endkey: `${prodAppId}${UNICODE_MAX}`, + } +} + /** * Generates a template ID. * @param ownerId The owner/user of the template, this could be global or a workspace level. @@ -115,6 +124,10 @@ export function generateTemplateID(ownerId: any) { return `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}` } +export function generateAppUserID(prodAppId: string, userId: string) { + return `${prodAppId}${SEPARATOR}${userId}` +} + /** * Gets parameters for retrieving templates. Owner ID must be specified, either global or a workspace level. */ @@ -442,15 +455,29 @@ export const getPlatformUrl = async (opts = { tenantAware: true }) => { export function pagination( data: any[], pageSize: number, - { paginate, property } = { paginate: true, property: "_id" } + { + paginate, + property, + getKey, + }: { + paginate: boolean + property: string + getKey?: (doc: any) => string | undefined + } = { + paginate: true, + property: "_id", + } ) { if (!paginate) { return { data, hasNextPage: false } } const hasNextPage = data.length > pageSize let nextPage = undefined + if (!getKey) { + getKey = (doc: any) => (property ? doc?.[property] : doc?._id) + } if (hasNextPage) { - nextPage = property ? data[pageSize]?.[property] : data[pageSize]?._id + nextPage = getKey(data[pageSize]) } return { data: data.slice(0, pageSize), diff --git a/packages/backend-core/src/db/views.js b/packages/backend-core/src/db/views.js index 1e8dd7ee77..baf1807ca5 100644 --- a/packages/backend-core/src/db/views.js +++ b/packages/backend-core/src/db/views.js @@ -56,6 +56,33 @@ exports.createNewUserEmailView = async () => { await db.put(designDoc) } +exports.createUserAppView = async () => { + const db = getGlobalDB() + let designDoc + try { + designDoc = await db.get("_design/database") + } catch (err) { + // no design doc, make one + designDoc = DesignDoc() + } + const view = { + // if using variables in a map function need to inject them before use + map: `function(doc) { + if (doc._id.startsWith("${DocumentTypes.USER}${SEPARATOR}") && doc.roles) { + for (let prodAppId of Object.keys(doc.roles)) { + let emitted = prodAppId + "${SEPARATOR}" + doc._id + emit(emitted, null) + } + } + }`, + } + designDoc.views = { + ...designDoc.views, + [ViewNames.USER_BY_APP]: view, + } + await db.put(designDoc) +} + exports.createApiKeyView = async () => { const db = getGlobalDB() let designDoc @@ -106,6 +133,7 @@ exports.queryGlobalView = async (viewName, params, db = null) => { [ViewNames.USER_BY_EMAIL]: exports.createNewUserEmailView, [ViewNames.BY_API_KEY]: exports.createApiKeyView, [ViewNames.USER_BY_BUILDERS]: exports.createUserBuildersView, + [ViewNames.USER_BY_APP]: exports.createUserAppView, } // can pass DB in if working with something specific if (!db) { diff --git a/packages/backend-core/src/errors/index.js b/packages/backend-core/src/errors/index.js index 58b4eea8c5..31ffd739a0 100644 --- a/packages/backend-core/src/errors/index.js +++ b/packages/backend-core/src/errors/index.js @@ -37,6 +37,7 @@ module.exports = { types, errors: { UsageLimitError: licensing.UsageLimitError, + FeatureDisabledError: licensing.FeatureDisabledError, HTTPError: http.HTTPError, }, getPublicError, diff --git a/packages/backend-core/src/errors/licensing.js b/packages/backend-core/src/errors/licensing.js index 0d8ce08146..85d207ac35 100644 --- a/packages/backend-core/src/errors/licensing.js +++ b/packages/backend-core/src/errors/licensing.js @@ -4,6 +4,7 @@ const type = "license_error" const codes = { USAGE_LIMIT_EXCEEDED: "usage_limit_exceeded", + FEATURE_DISABLED: "feature_disabled", } const context = { @@ -12,6 +13,11 @@ const context = { limitName: err.limitName, } }, + [codes.FEATURE_DISABLED]: err => { + return { + featureName: err.featureName, + } + }, } class UsageLimitError extends HTTPError { @@ -21,9 +27,17 @@ class UsageLimitError extends HTTPError { } } +class FeatureDisabledError extends HTTPError { + constructor(message, featureName) { + super(message, 400, codes.FEATURE_DISABLED, type) + this.featureName = featureName + } +} + module.exports = { type, codes, context, UsageLimitError, + FeatureDisabledError, } diff --git a/packages/backend-core/src/events/publishers/group.ts b/packages/backend-core/src/events/publishers/group.ts new file mode 100644 index 0000000000..d300873725 --- /dev/null +++ b/packages/backend-core/src/events/publishers/group.ts @@ -0,0 +1,64 @@ +import { publishEvent } from "../events" +import { + Event, + UserGroup, + GroupCreatedEvent, + GroupDeletedEvent, + GroupUpdatedEvent, + GroupUsersAddedEvent, + GroupUsersDeletedEvent, + GroupAddedOnboardingEvent, + UserGroupRoles, +} from "@budibase/types" + +export async function created(group: UserGroup, timestamp?: number) { + const properties: GroupCreatedEvent = { + groupId: group._id as string, + } + await publishEvent(Event.USER_GROUP_CREATED, properties, timestamp) +} + +export async function updated(group: UserGroup) { + const properties: GroupUpdatedEvent = { + groupId: group._id as string, + } + await publishEvent(Event.USER_GROUP_UPDATED, properties) +} + +export async function deleted(group: UserGroup) { + const properties: GroupDeletedEvent = { + groupId: group._id as string, + } + await publishEvent(Event.USER_GROUP_DELETED, properties) +} + +export async function usersAdded(count: number, group: UserGroup) { + const properties: GroupUsersAddedEvent = { + count, + groupId: group._id as string, + } + await publishEvent(Event.USER_GROUP_USERS_ADDED, properties) +} + +export async function usersDeleted(emails: string[], group: UserGroup) { + const properties: GroupUsersDeletedEvent = { + count: emails.length, + groupId: group._id as string, + } + await publishEvent(Event.USER_GROUP_USERS_REMOVED, properties) +} + +export async function createdOnboarding(groupId: string) { + const properties: GroupAddedOnboardingEvent = { + groupId: groupId, + onboarding: true, + } + await publishEvent(Event.USER_GROUP_ONBOARDING, properties) +} + +export async function permissionsEdited(roles: UserGroupRoles) { + const properties: UserGroupRoles = { + ...roles, + } + await publishEvent(Event.USER_GROUP_PERMISSIONS_EDITED, properties) +} diff --git a/packages/backend-core/src/events/publishers/index.ts b/packages/backend-core/src/events/publishers/index.ts index 65785d4d8b..57fd0bf8e2 100644 --- a/packages/backend-core/src/events/publishers/index.ts +++ b/packages/backend-core/src/events/publishers/index.ts @@ -17,3 +17,4 @@ export * as user from "./user" export * as view from "./view" export * as installation from "./installation" export * as backfill from "./backfill" +export * as group from "./group" diff --git a/packages/backend-core/src/featureFlags/index.js b/packages/backend-core/src/featureFlags/index.js index c050cbdfef..103ac4df59 100644 --- a/packages/backend-core/src/featureFlags/index.js +++ b/packages/backend-core/src/featureFlags/index.js @@ -50,4 +50,5 @@ exports.getTenantFeatureFlags = tenantId => { exports.FeatureFlag = { LICENSING: "LICENSING", GOOGLE_SHEETS: "GOOGLE_SHEETS", + USER_GROUPS: "USER_GROUPS", } diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index ab89eed3b2..35777ae817 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -3,6 +3,7 @@ const errorClasses = errors.errors import * as events from "./events" import * as migrations from "./migrations" import * as users from "./users" +import * as roles from "./security/roles" import * as accounts from "./cloud/accounts" import * as installation from "./installation" import env from "./environment" @@ -51,6 +52,7 @@ const core = { installation, errors, logging, + roles, ...errorClasses, } diff --git a/packages/backend-core/src/logging.ts b/packages/backend-core/src/logging.ts index 8eda15ac79..3fc79a5fe7 100644 --- a/packages/backend-core/src/logging.ts +++ b/packages/backend-core/src/logging.ts @@ -15,11 +15,22 @@ export function logAlert(message: string, e?: any) { console.error(`bb-alert: ${message} ${errorJson}`) } +export function logAlertWithInfo( + message: string, + db: string, + id: string, + error: any +) { + message = `${message} - db: ${db} - doc: ${id} - error: ` + logAlert(message, error) +} + export function logWarn(message: string) { console.warn(`bb-warn: ${message}`) } export default { logAlert, + logAlertWithInfo, logWarn, } diff --git a/packages/backend-core/src/middleware/adminOnly.js b/packages/backend-core/src/middleware/adminOnly.js new file mode 100644 index 0000000000..4bfdf83848 --- /dev/null +++ b/packages/backend-core/src/middleware/adminOnly.js @@ -0,0 +1,9 @@ +module.exports = async (ctx, next) => { + if ( + !ctx.internal && + (!ctx.user || !ctx.user.admin || !ctx.user.admin.global) + ) { + ctx.throw(403, "Admin user only endpoint.") + } + return next() +} diff --git a/packages/backend-core/src/middleware/index.js b/packages/backend-core/src/middleware/index.js index 1721d56a3c..9d94bf5763 100644 --- a/packages/backend-core/src/middleware/index.js +++ b/packages/backend-core/src/middleware/index.js @@ -9,7 +9,8 @@ const tenancy = require("./tenancy") const internalApi = require("./internalApi") const datasourceGoogle = require("./passport/datasource/google") const csrf = require("./csrf") - +const adminOnly = require("./adminOnly") +const joiValidator = require("./joi-validator") module.exports = { google, oidc, @@ -25,4 +26,6 @@ module.exports = { google: datasourceGoogle, }, csrf, + adminOnly, + joiValidator, } diff --git a/packages/backend-core/src/middleware/joi-validator.js b/packages/backend-core/src/middleware/joi-validator.js new file mode 100644 index 0000000000..1686b0e727 --- /dev/null +++ b/packages/backend-core/src/middleware/joi-validator.js @@ -0,0 +1,28 @@ +function validate(schema, property) { + // Return a Koa middleware function + return (ctx, next) => { + if (!schema) { + return next() + } + let params = null + if (ctx[property] != null) { + params = ctx[property] + } else if (ctx.request[property] != null) { + params = ctx.request[property] + } + const { error } = schema.validate(params) + if (error) { + ctx.throw(400, `Invalid ${property} - ${error.message}`) + return + } + return next() + } +} + +module.exports.body = schema => { + return validate(schema, "body") +} + +module.exports.params = schema => { + return validate(schema, "params") +} diff --git a/packages/backend-core/src/objectStore/index.ts b/packages/backend-core/src/objectStore/index.ts index a7e0b0c134..503ab9bca0 100644 --- a/packages/backend-core/src/objectStore/index.ts +++ b/packages/backend-core/src/objectStore/index.ts @@ -75,9 +75,11 @@ export const ObjectStore = (bucket: any) => { s3ForcePathStyle: true, signatureVersion: "v4", apiVersion: "2006-03-01", - params: { + } + if (bucket) { + config.params = { Bucket: sanitizeBucket(bucket), - }, + } } if (env.MINIO_URL) { config.endpoint = env.MINIO_URL @@ -292,6 +294,7 @@ export const uploadDirectory = async ( } } await Promise.all(uploads) + return files } exports.downloadTarballDirect = async (url: string, path: string) => { diff --git a/packages/backend-core/src/security/roles.js b/packages/backend-core/src/security/roles.js index 7c57cadcbf..44dc4f2d3e 100644 --- a/packages/backend-core/src/security/roles.js +++ b/packages/backend-core/src/security/roles.js @@ -76,7 +76,7 @@ function isBuiltin(role) { /** * Works through the inheritance ranks to see how far up the builtin stack this ID is. */ -function builtinRoleToNumber(id) { +exports.builtinRoleToNumber = id => { const builtins = exports.getBuiltinRoles() const MAX = Object.values(BUILTIN_IDS).length + 1 if (id === BUILTIN_IDS.ADMIN || id === BUILTIN_IDS.BUILDER) { @@ -104,7 +104,8 @@ exports.lowerBuiltinRoleID = (roleId1, roleId2) => { if (!roleId2) { return roleId1 } - return builtinRoleToNumber(roleId1) > builtinRoleToNumber(roleId2) + return exports.builtinRoleToNumber(roleId1) > + exports.builtinRoleToNumber(roleId2) ? roleId2 : roleId1 } diff --git a/packages/backend-core/src/users.js b/packages/backend-core/src/users.js index 0c1350a674..34d546a8bb 100644 --- a/packages/backend-core/src/users.js +++ b/packages/backend-core/src/users.js @@ -1,4 +1,9 @@ -const { ViewNames } = require("./db/utils") +const { + ViewNames, + getUsersByAppParams, + getProdAppID, + generateAppUserID, +} = require("./db/utils") const { queryGlobalView } = require("./db/views") const { UNICODE_MAX } = require("./db/constants") @@ -13,12 +18,32 @@ exports.getGlobalUserByEmail = async email => { throw "Must supply an email address to view" } - const response = await queryGlobalView(ViewNames.USER_BY_EMAIL, { + return await queryGlobalView(ViewNames.USER_BY_EMAIL, { key: email.toLowerCase(), include_docs: true, }) +} - return response +exports.searchGlobalUsersByApp = async (appId, opts) => { + if (typeof appId !== "string") { + throw new Error("Must provide a string based app ID") + } + const params = getUsersByAppParams(appId, { + include_docs: true, + }) + params.startkey = opts && opts.startkey ? opts.startkey : params.startkey + let response = await queryGlobalView(ViewNames.USER_BY_APP, params) + if (!response) { + response = [] + } + return Array.isArray(response) ? response : [response] +} + +exports.getGlobalUserByAppPage = (appId, user) => { + if (!user) { + return + } + return generateAppUserID(getProdAppID(appId), user._id) } /** diff --git a/packages/backend-core/tests/utilities/mocks/events.js b/packages/backend-core/tests/utilities/mocks/events.js index a4055cc5ea..415d59019d 100644 --- a/packages/backend-core/tests/utilities/mocks/events.js +++ b/packages/backend-core/tests/utilities/mocks/events.js @@ -89,6 +89,14 @@ jest.spyOn(events.user, "passwordUpdated") jest.spyOn(events.user, "passwordResetRequested") jest.spyOn(events.user, "passwordReset") +jest.spyOn(events.group, "created") +jest.spyOn(events.group, "updated") +jest.spyOn(events.group, "deleted") +jest.spyOn(events.group, "usersAdded") +jest.spyOn(events.group, "usersDeleted") +jest.spyOn(events.group, "createdOnboarding") +jest.spyOn(events.group, "permissionsEdited") + jest.spyOn(events.serve, "servedBuilder") jest.spyOn(events.serve, "servedApp") jest.spyOn(events.serve, "servedAppPreview") diff --git a/packages/bbui/package.json b/packages/bbui/package.json index d28ba65e46..fdccebe2df 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,7 +38,7 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "^1.2.1", - "@budibase/string-templates": "^1.1.31", + "@budibase/string-templates": "1.1.33-alpha.0", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/bbui/src/Avatar/Avatar.svelte b/packages/bbui/src/Avatar/Avatar.svelte index f8acd9024c..136a4fe24b 100644 --- a/packages/bbui/src/Avatar/Avatar.svelte +++ b/packages/bbui/src/Avatar/Avatar.svelte @@ -4,7 +4,7 @@ ["XXS", "--spectrum-alias-avatar-size-50"], ["XS", "--spectrum-alias-avatar-size-75"], ["S", "--spectrum-alias-avatar-size-200"], - ["M", "--spectrum-alias-avatar-size-300"], + ["M", "--spectrum-alias-avatar-size-400"], ["L", "--spectrum-alias-avatar-size-500"], ["XL", "--spectrum-alias-avatar-size-600"], ["XXL", "--spectrum-alias-avatar-size-700"], @@ -13,6 +13,19 @@ export let url = "" export let disabled = false export let initials = "JD" + + const DefaultColor = "#3aab87" + + $: color = getColor(initials) + + const getColor = initials => { + if (!initials?.length) { + return DefaultColor + } + const code = initials[0].toLowerCase().charCodeAt(0) + const hue = ((code % 26) / 26) * 360 + return `hsl(${hue}, 50%, 50%)` + } {#if url} @@ -25,10 +38,11 @@ /> {:else}
{initials || ""}
@@ -40,7 +54,6 @@ display: grid; place-items: center; font-weight: 600; - background: #3aab87; border-radius: 50%; overflow: hidden; user-select: none; diff --git a/packages/bbui/src/Form/Core/InputDropdown.svelte b/packages/bbui/src/Form/Core/InputDropdown.svelte new file mode 100644 index 0000000000..8865ee3ddc --- /dev/null +++ b/packages/bbui/src/Form/Core/InputDropdown.svelte @@ -0,0 +1,228 @@ + + +
+
+ {#if error} + + {/if} + + +
+
+ + {#if open} +
(open = false)} + transition:fly|local={{ y: -20, duration: 200 }} + class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open" + > +
    + {#each options as option, idx} +
  • onPick(getOptionValue(option, idx))} + > + + {getOptionLabel(option, idx)} + + +
  • + {/each} +
+
+ {/if} +
+
+ + diff --git a/packages/bbui/src/Form/Core/Multiselect.svelte b/packages/bbui/src/Form/Core/Multiselect.svelte index 3eb1add267..9dd5a25a4f 100644 --- a/packages/bbui/src/Form/Core/Multiselect.svelte +++ b/packages/bbui/src/Form/Core/Multiselect.svelte @@ -13,6 +13,7 @@ export let readonly = false export let autocomplete = false export let sort = false + export let autoWidth = false const dispatch = createEventDispatcher() $: selectedLookupMap = getSelectedLookupMap(value) @@ -85,4 +86,5 @@ {getOptionValue} onSelectOption={toggleOption} {sort} + {autoWidth} /> diff --git a/packages/bbui/src/Form/Core/PickerDropdown.svelte b/packages/bbui/src/Form/Core/PickerDropdown.svelte new file mode 100644 index 0000000000..fbe43717ba --- /dev/null +++ b/packages/bbui/src/Form/Core/PickerDropdown.svelte @@ -0,0 +1,436 @@ + + +
+
+ {#if iconData} + + + + {/if} + (primaryOpen = true)} + on:blur + on:focus + on:input + on:keyup + on:blur={onBlur} + on:input={onInput} + on:keyup={updateValueOnEnter} + value={primaryLabel || ""} + placeholder={placeholder || ""} + {disabled} + {readonly} + class="spectrum-Textfield-input spectrum-InputGroup-input" + class:labelPadding={iconData} + /> + {#if primaryValue} + + {/if} +
+ {#if primaryOpen} +
(primaryOpen = false)} + transition:fly|local={{ y: -20, duration: 200 }} + class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open" + class:auto-width={autoWidth} + class:is-full-width={!secondaryOptions.length} + > + {#if autocomplete} + updateSearch(event)} + {disabled} + placeholder="Search" + /> + {/if} + +
    + {#if placeholderOption} +
  • onSelectOption(null)} + > + {placeholderOption} + +
  • + {/if} + {#each groupTitles as title} +
    + {title} +
    + {#if primaryOptions} + {#each primaryOptions[title].data as option, idx} +
  • + onPickPrimary({ + value: primaryOptions[title].getValue(option), + label: primaryOptions[title].getLabel(option), + })} + > + {#if primaryOptions[title].getIcon(option)} +
    +
    + +
    +
    + {:else if getPrimaryOptionColour(option, idx)} + + + + {/if} + + + {primaryOptions[title].getLabel(option)} + + + + {#if getPrimaryOptionIcon(option, idx) && getPrimaryOptionColour(option, idx)} + + + + {/if} + +
  • + {/each} + {/if} + {/each} +
+
+ {/if} + {#if secondaryOptions.length} +
+ + {#if secondaryOpen} +
(secondaryOpen = false)} + transition:fly|local={{ y: -20, duration: 200 }} + class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open" + style="width: 30%" + > +
    + {#each secondaryOptions as option, idx} +
  • + onPickSecondary(getSecondaryOptionValue(option, idx))} + > + {#if getSecondaryOptionColour(option, idx)} + + + + {/if} + + + {getSecondaryOptionLabel(option, idx)} + + +
  • + {/each} +
+
+ {/if} +
+ {/if} +
+ + diff --git a/packages/bbui/src/Form/Core/Select.svelte b/packages/bbui/src/Form/Core/Select.svelte index 81d7ec8e6c..f549f58d0c 100644 --- a/packages/bbui/src/Form/Core/Select.svelte +++ b/packages/bbui/src/Form/Core/Select.svelte @@ -17,7 +17,6 @@ export let autoWidth = false export let autocomplete = false export let sort = false - const dispatch = createEventDispatcher() let open = false $: fieldText = getFieldText(value, options, placeholder) diff --git a/packages/bbui/src/Form/InputDropdown.svelte b/packages/bbui/src/Form/InputDropdown.svelte new file mode 100644 index 0000000000..73516ea37c --- /dev/null +++ b/packages/bbui/src/Form/InputDropdown.svelte @@ -0,0 +1,55 @@ + + + + + diff --git a/packages/bbui/src/Form/Multiselect.svelte b/packages/bbui/src/Form/Multiselect.svelte index 957dcccddf..7bcf22aa06 100644 --- a/packages/bbui/src/Form/Multiselect.svelte +++ b/packages/bbui/src/Form/Multiselect.svelte @@ -14,7 +14,7 @@ export let getOptionLabel = option => option export let getOptionValue = option => option export let sort = false - + export let autoWidth = false const dispatch = createEventDispatcher() const onChange = e => { value = e.detail @@ -33,6 +33,7 @@ {sort} {getOptionLabel} {getOptionValue} + {autoWidth} on:change={onChange} on:click /> diff --git a/packages/bbui/src/Form/PickerDropdown.svelte b/packages/bbui/src/Form/PickerDropdown.svelte new file mode 100644 index 0000000000..63a11c5873 --- /dev/null +++ b/packages/bbui/src/Form/PickerDropdown.svelte @@ -0,0 +1,132 @@ + + + + + diff --git a/packages/bbui/src/IconPicker/IconPicker.svelte b/packages/bbui/src/IconPicker/IconPicker.svelte new file mode 100644 index 0000000000..0e71be2c33 --- /dev/null +++ b/packages/bbui/src/IconPicker/IconPicker.svelte @@ -0,0 +1,177 @@ + + +
+
(open = true)}> +
+ +
+
+ {#if open} +
(open = false)} + transition:fly={{ y: -20, duration: 200 }} + class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open" + class:spectrum-Popover--align-right={alignRight} + > + {#each iconList as icon} +
+
{icon.label}
+
+ {#each icon.icons as icon} +
{ + onChange(icon) + }} + > + +
+ {/each} +
+
+ {/each} +
+ {/if} +
+ + diff --git a/packages/bbui/src/List/Items/DetailSummary.svench b/packages/bbui/src/List/Items/DetailSummary.svench deleted file mode 100644 index 48fb8f7df8..0000000000 --- a/packages/bbui/src/List/Items/DetailSummary.svench +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - -
- - 1 - 2 - 3 - 4 - - - 1 - 2 - 3 - 4 - -
-
- - -
- - 1 - 2 - 3 - 4 - - - 1 - 2 - 3 - 4 - -
-
diff --git a/packages/bbui/src/List/List.svelte b/packages/bbui/src/List/List.svelte new file mode 100644 index 0000000000..243b04da50 --- /dev/null +++ b/packages/bbui/src/List/List.svelte @@ -0,0 +1,28 @@ + + +
+ {#if title} +
+ {title} +
+ {/if} +
+ +
+
+ + diff --git a/packages/bbui/src/List/ListItem.svelte b/packages/bbui/src/List/ListItem.svelte new file mode 100644 index 0000000000..76a83e7b08 --- /dev/null +++ b/packages/bbui/src/List/ListItem.svelte @@ -0,0 +1,92 @@ + + +
+
+ {#if icon} +
+ +
+ {/if} + {#if avatar} + + {/if} + {#if title} + {title} + {/if} + {#if subtitle} + + {/if} +
+
+ +
+
+ + diff --git a/packages/bbui/src/Table/Table.svelte b/packages/bbui/src/Table/Table.svelte index e01d84e123..c929e02d86 100644 --- a/packages/bbui/src/Table/Table.svelte +++ b/packages/bbui/src/Table/Table.svelte @@ -37,6 +37,7 @@ export let autoSortColumns = true export let compact = false export let customPlaceholder = false + export let showHeaderBorder = true export let placeholderText = "No rows found" const dispatch = createEventDispatcher() @@ -286,6 +287,7 @@
{#if showEditColumn}
{#if allowSelectRows} @@ -301,6 +303,7 @@ {#each fields as field}
{#if showEditColumn}
{ toggleSelectRow(row) @@ -481,6 +485,18 @@ .spectrum-Table-headCell:last-of-type { border-right: var(--table-border); } + + .noBorderHeader { + border-top: none !important; + border-right: none !important; + border-left: none !important; + } + + .noBorderCheckbox { + border-top: none !important; + border-right: none !important; + } + .spectrum-Table-headCell--alignCenter { justify-content: center; } @@ -499,7 +515,7 @@ z-index: 3; } .spectrum-Table-headCell .title { - overflow: hidden; + overflow: visible; text-overflow: ellipsis; } .spectrum-Table-headCell:hover .spectrum-Table-editIcon { @@ -562,7 +578,7 @@ gap: 4px; border-bottom: 1px solid var(--spectrum-alias-border-color-mid); background-color: var(--table-bg); - z-index: 1; + z-index: auto; } .spectrum-Table-cell--divider { padding-right: var(--cell-padding); @@ -570,6 +586,7 @@ .spectrum-Table-cell--divider + .spectrum-Table-cell { padding-left: var(--cell-padding); } + .spectrum-Table-cell--edit { position: sticky; left: 0; diff --git a/packages/bbui/src/index.js b/packages/bbui/src/index.js index 7d5baad474..b45f3e9ed6 100644 --- a/packages/bbui/src/index.js +++ b/packages/bbui/src/index.js @@ -23,6 +23,8 @@ export { default as Icon, directions } from "./Icon/Icon.svelte" export { default as Toggle } from "./Form/Toggle.svelte" export { default as RadioGroup } from "./Form/RadioGroup.svelte" export { default as Checkbox } from "./Form/Checkbox.svelte" +export { default as InputDropdown } from "./Form/InputDropdown.svelte" +export { default as PickerDropdown } from "./Form/PickerDropdown.svelte" export { default as DetailSummary } from "./DetailSummary/DetailSummary.svelte" export { default as Popover } from "./Popover/Popover.svelte" export { default as ProgressBar } from "./ProgressBar/ProgressBar.svelte" @@ -58,12 +60,15 @@ export { default as Pagination } from "./Pagination/Pagination.svelte" export { default as Badge } from "./Badge/Badge.svelte" export { default as StatusLight } from "./StatusLight/StatusLight.svelte" export { default as ColorPicker } from "./ColorPicker/ColorPicker.svelte" +export { default as IconPicker } from "./IconPicker/IconPicker.svelte" export { default as InlineAlert } from "./InlineAlert/InlineAlert.svelte" export { default as Banner } from "./Banner/Banner.svelte" export { default as BannerDisplay } from "./Banner/BannerDisplay.svelte" export { default as MarkdownEditor } from "./Markdown/MarkdownEditor.svelte" export { default as MarkdownViewer } from "./Markdown/MarkdownViewer.svelte" export { default as RichTextField } from "./Form/RichTextField.svelte" +export { default as List } from "./List/List.svelte" +export { default as ListItem } from "./List/ListItem.svelte" export { default as IconSideNav } from "./IconSideNav/IconSideNav.svelte" export { default as IconSideNavItem } from "./IconSideNav/IconSideNavItem.svelte" export { default as Slider } from "./Form/Slider.svelte" @@ -71,6 +76,7 @@ export { default as Slider } from "./Form/Slider.svelte" // Renderers export { default as BoldRenderer } from "./Table/BoldRenderer.svelte" export { default as CodeRenderer } from "./Table/CodeRenderer.svelte" +export { default as InternalRenderer } from "./Table/InternalRenderer.svelte" // Typography export { default as Body } from "./Typography/Body.svelte" diff --git a/packages/bbui/yarn.lock b/packages/bbui/yarn.lock index d301afea53..6200487df3 100644 --- a/packages/bbui/yarn.lock +++ b/packages/bbui/yarn.lock @@ -28,6 +28,46 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@rollup/plugin-commonjs@^16.0.0": version "16.0.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f" @@ -340,6 +380,11 @@ acorn@^7.3.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.5.0: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + alphanum-sort@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -447,9 +492,9 @@ browserslist@^4.0.0: node-releases "^1.1.71" buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== builtin-modules@^3.1.0: version "3.2.0" @@ -2372,16 +2417,15 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -"source-map-fast@npm:source-map@0.7.3", source-map@~0.7.2: - name source-map-fast +"source-map-fast@npm:source-map@0.7.3": version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -source-map-support@~0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -2485,9 +2529,9 @@ svelte-portal@^1.0.0: integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== svelte@^3.38.2: - version "3.38.2" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.38.2.tgz#55e5c681f793ae349b5cc2fe58e5782af4275ef5" - integrity sha512-q5Dq0/QHh4BLJyEVWGe7Cej5NWs040LWjMbicBGZ+3qpFWJ1YObRmUDZKbbovddLC9WW7THTj3kYbTOFmU9fbg== + version "3.49.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" + integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== svgo@^1.0.0: version "1.3.2" @@ -2509,13 +2553,14 @@ svgo@^1.0.0: util.promisify "~1.0.0" terser@^5.0.0: - version "5.6.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.6.1.tgz#a48eeac5300c0a09b36854bf90d9c26fb201973c" - integrity sha512-yv9YLFQQ+3ZqgWCUk+pvNJwgUTdlIxUk1WTN+RnaFJe2L7ipG2csPT0ra2XRm7Cs8cxN7QXmK1rFzEwYEQkzXw== + version "5.14.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" + integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.19" + source-map-support "~0.5.20" timsort@^0.3.0: version "0.3.0" @@ -2580,7 +2625,7 @@ unquote@~1.1.1: util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== util.promisify@~1.0.0: version "1.0.1" diff --git a/packages/builder/cypress/integration/addMultiOptionDatatype.spec.js b/packages/builder/cypress/integration/addMultiOptionDatatype.spec.js index 32f62efe1f..f436f3ff39 100644 --- a/packages/builder/cypress/integration/addMultiOptionDatatype.spec.js +++ b/packages/builder/cypress/integration/addMultiOptionDatatype.spec.js @@ -17,16 +17,15 @@ filterTests(['all'], () => { it("should add form with multi select picker, containing 5 options", () => { cy.navigateToFrontend() // Add data provider - cy.get(interact.CATEGORY_DATA, { timeout: 500 }).click() - cy.get(interact.COMPONENT_DATA_PROVIDER).click() + cy.searchAndAddComponent("Data Provider") cy.get(interact.DATASOURCE_PROP_CONTROL).click() cy.get(interact.DROPDOWN).contains("Multi Data").click() // Add Form with schema to match table - cy.addComponent("Form", "Form") + cy.searchAndAddComponent("Form") cy.get(interact.DATASOURCE_PROP_CONTROL).click() cy.get(interact.DROPDOWN).contains("Multi Data").click() // Add multi-select picker to form - cy.addComponent("Form", "Multi-select Picker").then(componentId => { + cy.searchAndAddComponent("Multi-select Picker").then(componentId => { cy.get(interact.DATASOURCE_FIELD_CONTROL).type("Test Data").type("{enter}") cy.wait(1000) cy.getComponent(componentId).contains("Choose some options").click() diff --git a/packages/builder/cypress/integration/addRadioButtons.spec.js b/packages/builder/cypress/integration/addRadioButtons.spec.js index 578b519341..91cfd0c7fa 100644 --- a/packages/builder/cypress/integration/addRadioButtons.spec.js +++ b/packages/builder/cypress/integration/addRadioButtons.spec.js @@ -10,15 +10,13 @@ filterTests(['all'], () => { it("should add Radio Buttons options picker on form, add data, and confirm", () => { cy.navigateToFrontend() - cy.wait(500) - cy.addComponent("Form", "Form") - cy.addComponent("Form", "Options Picker").then((componentId) => { - // Provide field setting + cy.searchAndAddComponent("Form") + cy.searchAndAddComponent("Options Picker").then((componentId) => { + // Provide field setting cy.get(interact.DATASOURCE_FIELD_CONTROL).type("1") // Open dropdown and select Radio buttons cy.get(interact.OPTION_TYPE_PROP_CONTROL).click().then(() => { cy.get(interact.SPECTRUM_POPOVER).contains('Radio buttons') - .wait(500) .click() }) const radioButtonsTotal = 3 @@ -32,8 +30,8 @@ filterTests(['all'], () => { const addRadioButtonData = (totalRadioButtons) => { cy.get(interact.OPTION_SOURCE_PROP_CONROL).click().then(() => { cy.get(interact.SPECTRUM_POPOVER).contains('Custom') - .wait(500) .click() + .wait(1000) }) cy.addCustomSourceOptions(totalRadioButtons) } diff --git a/packages/builder/cypress/integration/adminAndManagement/accountPortals.spec.js b/packages/builder/cypress/integration/adminAndManagement/accountPortals.spec.js index 491a4abc44..7b2c68089a 100644 --- a/packages/builder/cypress/integration/adminAndManagement/accountPortals.spec.js +++ b/packages/builder/cypress/integration/adminAndManagement/accountPortals.spec.js @@ -19,9 +19,14 @@ filterTests(["smoke", "all"], () => { cy.wait(500) // Reset password - cy.get(".spectrum-ActionButton-label", { timeout: 2000 }).contains("Force password reset").click({ force: true }) + cy.get(".title").within(() => { + cy.get(interact.SPECTRUM_ICON).click({ force: true }) + }) + cy.get(interact.SPECTRUM_MENU).within(() => { + cy.get(interact.SPECTRUM_MENU_ITEM).contains("Force Password Reset").click({ force: true }) + }) - cy.get(".spectrum-Dialog-grid") + cy.get(interact.SPECTRUM_DIALOG_GRID) .find(interact.SPECTRUM_TEXTFIELD_INPUT).invoke('val').as('pwd') cy.get(interact.SPECTRUM_BUTTON).contains("Reset password").click({ force: true }) @@ -39,23 +44,14 @@ filterTests(["smoke", "all"], () => { cy.logoutNoAppGrid() }) - it("should verify Admin Portal", () => { + xit("should verify Admin Portal", () => { cy.login() - cy.contains("Users").click() - cy.contains("bbuser").click() - - // Enable Development & Administration access - cy.wait(500) - for (let i = 4; i < 6; i++) { - cy.get(interact.FIELD).eq(i).within(() => { - cy.get(interact.SPECTRUM_SWITCH_INPUT).click({ force: true }) - cy.get(interact.SPECTRUM_SWITCH_INPUT).should('be.enabled') - }) - } + // Configure user role + cy.setUserRole("bbuser", "Admin") bbUserLogin() // Verify available options for Admin portal - cy.get(".spectrum-SideNav") + cy.get(interact.SPECTRUM_SIDENAV) .should('contain', 'Apps') //.and('contain', 'Usage') .and('contain', 'Users') @@ -72,13 +68,7 @@ filterTests(["smoke", "all"], () => { it("should verify Development Portal", () => { // Only Development access should be enabled cy.login() - cy.contains("Users").click() - cy.contains("bbuser").click() - cy.wait(500) - cy.get(interact.FIELD).eq(5).within(() => { - cy.get(interact.SPECTRUM_SWITCH_INPUT).click({ force: true }) - }) - + cy.setUserRole("bbuser", "Developer") bbUserLogin() // Verify available options for Admin portal @@ -99,13 +89,7 @@ filterTests(["smoke", "all"], () => { it("should verify Standard Portal", () => { // Development access should be disabled (Admin access is already disabled) cy.login() - cy.contains("Users").click() - cy.contains("bbuser").click() - cy.wait(500) - cy.get(interact.FIELD).eq(4).within(() => { - cy.get(interact.SPECTRUM_SWITCH_INPUT).click({ force: true }) - }) - + cy.setUserRole("bbuser", "App User") bbUserLogin() // Verify Standard Portal diff --git a/packages/builder/cypress/integration/adminAndManagement/userManagement.spec.js b/packages/builder/cypress/integration/adminAndManagement/userManagement.spec.js index 562e1e149f..3dfffb1d39 100644 --- a/packages/builder/cypress/integration/adminAndManagement/userManagement.spec.js +++ b/packages/builder/cypress/integration/adminAndManagement/userManagement.spec.js @@ -15,25 +15,16 @@ filterTests(["smoke", "all"], () => { cy.get(interact.SPECTRUM_TABLE).should("contain", "bbuser") }) - it("should confirm basic permission for a New User", () => { - // Basic permission = development & administraton disabled + it("should confirm App User role for a New User", () => { cy.contains("bbuser").click() - // Confirm development and admin access are disabled - for (let i = 4; i < 6; i++) { - cy.wait(500) - cy.get(interact.FIELD).eq(i).within(() => { - //cy.get(interact.SPECTRUM_SWITCH_INPUT).should('be.disabled') - cy.get(".spectrum-Switch-switch").should('not.be.checked') - }) - } - // Existing apps appear within the No Access table - cy.get(interact.SPECTRUM_TABLE, { timeout: 500 }).eq(1).should("not.contain", "No rows found") - // Configure roles table should not contain apps - cy.get(interact.SPECTRUM_TABLE).eq(0).contains("No rows found") + cy.get(".spectrum-Form-itemField").eq(2).should('contain', 'App User') + + // User should not have app access + cy.get(interact.LIST_ITEMS, { timeout: 500 }).should("contain", "No apps") }) if (Cypress.env("TEST_ENV")) { - it("should assign role types", () => { + xit("should assign role types", () => { // 3 apps minimum required - to assign an app to each role type cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) .its("body") @@ -57,6 +48,7 @@ filterTests(["smoke", "all"], () => { cy.visit(`${Cypress.config().baseUrl}/builder`, { timeout: 5000}) cy.get(interact.SPECTRUM_SIDENAV).contains("Users").click() cy.get(interact.SPECTRUM_TABLE, { timeout: 1000 }).contains("bbuser").click() + cy.get(interact.SPECTRUM_HEADING).contains("bbuser", { timeout: 2000}) for (let i = 0; i < 3; i++) { cy.get(interact.SPECTRUM_TABLE, { timeout: 3000}) .eq(1) @@ -95,7 +87,7 @@ filterTests(["smoke", "all"], () => { }) }) - it("should unassign role types", () => { + xit("should unassign role types", () => { // Set each app within Configure roles table to 'No Access' cy.get(interact.SPECTRUM_TABLE) .eq(0) @@ -124,7 +116,7 @@ filterTests(["smoke", "all"], () => { }) } - it("should enable Developer access and verify application access", () => { + xit("should enable Developer access and verify application access", () => { // Enable Developer access cy.get(interact.FIELD) .eq(4) @@ -156,7 +148,7 @@ filterTests(["smoke", "all"], () => { }) }) - it("should disable Developer access and verify application access", () => { + xit("should disable Developer access and verify application access", () => { // Disable Developer access cy.get(interact.FIELD) .eq(4) @@ -174,12 +166,12 @@ filterTests(["smoke", "all"], () => { it("Should edit user details within user details page", () => { // Add First name - cy.get(interact.FIELD, { timeout: 1000 }).eq(2).within(() => { + cy.get(interact.FIELD, { timeout: 1000 }).eq(0).within(() => { cy.wait(500) cy.get(interact.SPECTRUM_TEXTFIELD_INPUT, { timeout: 1000 }).wait(500).clear().click().type("bb") }) // Add Last name - cy.get(interact.FIELD, { timeout: 1000 }).eq(3).within(() => { + cy.get(interact.FIELD, { timeout: 1000 }).eq(1).within(() => { cy.wait(500) cy.get(interact.SPECTRUM_TEXTFIELD_INPUT, { timeout: 1000 }).click().wait(500).clear().type("test") }) @@ -188,16 +180,21 @@ filterTests(["smoke", "all"], () => { cy.reload() // Confirm details have been saved - cy.get(interact.FIELD, { timeout: 1000 }).eq(2).within(() => { + cy.get(interact.FIELD, { timeout: 1000 }).eq(0).within(() => { cy.get(interact.SPECTRUM_TEXTFIELD_INPUT).should('have.value', "bb") }) - cy.get(interact.FIELD, { timeout: 1000 }).eq(3).within(() => { + cy.get(interact.FIELD, { timeout: 1000 }).eq(1).within(() => { cy.get(interact.SPECTRUM_TEXTFIELD_INPUT, { timeout: 1000 }).should('have.value', "test") }) }) it("should reset the users password", () => { - cy.get(interact.REGENERATE, { timeout: 500 }).contains("Force password reset").click({ force: true }) + cy.get(".title").within(() => { + cy.get(interact.SPECTRUM_ICON).click({ force: true }) + }) + cy.get(interact.SPECTRUM_MENU).within(() => { + cy.get(interact.SPECTRUM_MENU_ITEM).contains("Force Password Reset").click({ force: true }) + }) // Reset password modal cy.get(interact.SPECTRUM_DIALOG_GRID) diff --git a/packages/builder/cypress/integration/adminAndManagement/userSettings.spec.js b/packages/builder/cypress/integration/adminAndManagement/userSettings.spec.js index 95af9f7841..d388d9c7a5 100644 --- a/packages/builder/cypress/integration/adminAndManagement/userSettings.spec.js +++ b/packages/builder/cypress/integration/adminAndManagement/userSettings.spec.js @@ -19,10 +19,10 @@ filterTests(["smoke", "all"], () => { cy.contains("Users").click() cy.contains("test@test.com").click() - cy.get(interact.FIELD, { timeout: 1000 }).eq(2).within(() => { + cy.get(interact.FIELD, { timeout: 1000 }).eq(0).within(() => { cy.get(interact.SPECTRUM_TEXTFIELD_INPUT).should('have.value', fname) }) - cy.get(interact.FIELD).eq(3).within(() => { + cy.get(interact.FIELD).eq(1).within(() => { cy.get(interact.SPECTRUM_TEXTFIELD_INPUT).should('have.value', lname) }) }) diff --git a/packages/builder/cypress/integration/appOverview.spec.js b/packages/builder/cypress/integration/appOverview.spec.js index dbfce3ce63..feaace6fb6 100644 --- a/packages/builder/cypress/integration/appOverview.spec.js +++ b/packages/builder/cypress/integration/appOverview.spec.js @@ -205,7 +205,7 @@ filterTests(["all"], () => { cy.navigateToFrontend() - cy.addComponent("Elements", "Headline").then(componentId => { + cy.searchAndAddComponent("Headline").then(componentId => { cy.getComponent(componentId).should("exist") }) diff --git a/packages/builder/cypress/integration/autoScreensUI.spec.js b/packages/builder/cypress/integration/autoScreensUI.spec.js index ca997479ae..7a5dbef5a5 100644 --- a/packages/builder/cypress/integration/autoScreensUI.spec.js +++ b/packages/builder/cypress/integration/autoScreensUI.spec.js @@ -10,15 +10,10 @@ filterTests(['smoke', 'all'], () => { it("should disable the autogenerated screen options if no sources are available", () => { cy.createApp("First Test App", false) - cy.closeModal(); - cy.contains("Design").click() - cy.get(interact.LABEL_ADD_CIRCLE).click() - cy.get(interact.SPECTRUM_MODAL).within(() => { - cy.get(interact.ITEM_DISABLED).contains("Autogenerated screens") - cy.get(interact.CONFIRM_WRAP_SPE_BUTTON).should('be.disabled') - }) + cy.navigateToAutogeneratedModal() + cy.get(interact.CONFIRM_WRAP_SPE_BUTTON).should('be.disabled') cy.deleteAllApps() }); @@ -45,25 +40,25 @@ filterTests(['smoke', 'all'], () => { // Create Autogenerated screens from the internal table cy.createDatasourceScreen(["Cypress Tests"]) // Confirm screens have been auto generated - cy.get(interact.NAV_ITEMS_CONTAINER).contains("cypress-tests").click({ force: true }) - cy.get(interact.NAV_ITEMS_CONTAINER).should('contain', 'cypress-tests/:id') + cy.get(interact.BODY).should('contain', "cypress-tests") + .and('contain', 'cypress-tests/:id') .and('contain', 'cypress-tests/new/row') }) it("should generate multiple internal table screens at once", () => { - // Create a second internal table const initialTable = "Cypress Tests" const secondTable = "Table Two" + // Create a second internal table cy.createTable(secondTable) // Create Autogenerated screens from the internal tables cy.createDatasourceScreen([initialTable, secondTable]) // Confirm screens have been auto generated - cy.get(interact.NAV_ITEMS_CONTAINER).contains("cypress-tests").click({ force: true }) // Previously generated tables are suffixed with numbers - as expected - cy.get(interact.NAV_ITEMS_CONTAINER).should('contain', 'cypress-tests-2/:id') + cy.get(interact.BODY).should('contain', 'cypress-tests-2') + .and('contain', 'cypress-tests-2/:id') .and('contain', 'cypress-tests-2/new/row') - cy.get(interact.NAV_ITEMS_CONTAINER).contains("table-two").click() - cy.get(interact.NAV_ITEMS_CONTAINER).should('contain', 'table-two/:id') + .and('contain', 'table-two') + .and('contain', 'table-two/:id') .and('contain', 'table-two/new/row') }) @@ -73,17 +68,17 @@ filterTests(['smoke', 'all'], () => { cy.createTable("Table Four") cy.createDatasourceScreen(["Table Three", "Table Four"], "Admin") - cy.get(interact.NAV_ITEMS_CONTAINER).contains("table-three").click() - cy.get(interact.NAV_ITEMS_CONTAINER).should('contain', 'table-three/:id') + // Filter screens to Admin + cy.filterScreensAccessLevel('Admin') + + cy.get(interact.BODY).should('contain', 'table-three') + .and('contain', 'table-three/:id') .and('contain', 'table-three/new/row') - - cy.get(interact.NAV_ITEMS_CONTAINER).contains("table-four").click() - cy.get(interact.NAV_ITEMS_CONTAINER).should('contain', 'table-four/:id') + .and('contain', 'table-four') + .and('contain', 'table-four/:id') .and('contain', 'table-four/new/row') - - //The access level should now be set to admin. Previous screens should be filtered. - cy.get(interact.NAV_ITEMS_CONTAINER).contains("table-two").should('not.exist') - cy.get(interact.NAV_ITEMS_CONTAINER).contains("cypress-tests").should('not.exist') + .and('not.contain', 'table-two') + .and('not.contain', 'cypress-tests') }) if (Cypress.env("TEST_ENV")) { @@ -96,8 +91,8 @@ filterTests(['smoke', 'all'], () => { // Create Autogenerated screens from a MySQL table - MySQL contains books table cy.createDatasourceScreen(["books"]) - cy.get(interact.NAV_ITEMS_CONTAINER).contains("books").click() - cy.get(interact.NAV_ITEMS_CONTAINER).should('contain', 'books/:id') + cy.get(interact.BODY).should('contain', 'books') + .and('contain', 'books/:id') .and('contain', 'books/new/row') }) } diff --git a/packages/builder/cypress/integration/createApp.spec.js b/packages/builder/cypress/integration/createApp.spec.js index ca52c66e35..516489b093 100644 --- a/packages/builder/cypress/integration/createApp.spec.js +++ b/packages/builder/cypress/integration/createApp.spec.js @@ -13,7 +13,7 @@ filterTests(['smoke', 'all'], () => { it("should show the new user UI/UX", () => { cy.visit(`${Cypress.config().baseUrl}/builder/portal/apps/create`, { timeout: 5000 }) //added /portal/apps/create cy.wait(1000) - cy.get(interact.CREATE_APP_BUTTON).contains('Start from scratch').should("exist") + cy.get(interact.CREATE_APP_BUTTON, { timeout: 10000 }).contains('Start from scratch').should("exist") cy.get(interact.TEMPLATE_CATEGORY_FILTER).should("exist") cy.get(interact.TEMPLATE_CATEGORY).should("exist") @@ -100,24 +100,18 @@ filterTests(['smoke', 'all'], () => { }) it("should create the first application from scratch, using the users first name as the default app name", () => { - cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.visit(`${Cypress.config().baseUrl}/builder`, { timeout: 5000 }) cy.updateUserInformation("Ted", "Userman") cy.createApp("", false) - - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.applicationInAppTable("Teds app") cy.deleteApp("Teds app") - //Accomodate names that end in 'S' + // Accomodate names that end in 'S' cy.updateUserInformation("Chris", "Userman") cy.createApp("", false) - - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.applicationInAppTable("Chris app") cy.deleteApp("Chris app") diff --git a/packages/builder/cypress/integration/createBinding.spec.js b/packages/builder/cypress/integration/createBinding.spec.js index 5abe0b27d8..160f23d2d6 100644 --- a/packages/builder/cypress/integration/createBinding.spec.js +++ b/packages/builder/cypress/integration/createBinding.spec.js @@ -9,13 +9,13 @@ filterTests(['smoke', 'all'], () => { }) it("should add a current user binding", () => { - cy.addComponent("Elements", "Paragraph").then(() => { + cy.searchAndAddComponent("Paragraph").then(() => { addSettingBinding("text", "Current User._id") }) }) it("should handle an invalid binding", () => { - cy.addComponent("Elements", "Paragraph").then(componentId => { + cy.searchAndAddComponent("Paragraph").then(componentId => { // Cypress needs to escape curly brackets cy.get("[data-cy=setting-text] input") .type("{{}{{}{{} Current User._id {}}{}}") @@ -27,7 +27,7 @@ filterTests(['smoke', 'all'], () => { xit("should add a URL param binding", () => { const paramName = "foo" cy.createScreen(`/test/:${paramName}`) - cy.addComponent("Elements", "Paragraph").then(componentId => { + cy.searchAndAddComponent("Paragraph").then(componentId => { addSettingBinding("text", `URL.${paramName}`) // The builder preview pages don't have a real URL, so all we can do // is check that we were able to bind to the property, and that the @@ -37,7 +37,7 @@ filterTests(['smoke', 'all'], () => { }) it("should add a binding with a handlebars helper", () => { - cy.addComponent("Elements", "Paragraph").then(componentId => { + cy.searchAndAddComponent("Paragraph").then(componentId => { // Cypress needs to escape curly brackets cy.get("[data-cy=setting-text] input") .type("{{}{{} add 1 2 {}}{}}") diff --git a/packages/builder/cypress/integration/createComponents.spec.js b/packages/builder/cypress/integration/createComponents.spec.js index eff7fc216f..649a77e442 100644 --- a/packages/builder/cypress/integration/createComponents.spec.js +++ b/packages/builder/cypress/integration/createComponents.spec.js @@ -31,13 +31,13 @@ filterTests(["all"], () => { } it("should add a container", () => { - cy.addComponent("Layout", "Container").then(componentId => { + cy.searchAndAddComponent("Container").then(componentId => { cy.getComponent(componentId).should("exist") }) }) it("should add a headline", () => { - cy.addComponent("Elements", "Headline").then(componentId => { + cy.searchAndAddComponent("Headline").then(componentId => { headlineId = componentId cy.getComponent(headlineId).should("exist") }) @@ -63,11 +63,11 @@ filterTests(["all"], () => { }) it("should create a form and reset to match schema", () => { - cy.addComponent("Form", "Form").then(() => { + cy.searchAndAddComponent("Form").then(() => { cy.get("[data-cy=setting-dataSource]").contains("Custom").click() cy.get(interact.DROPDOWN).contains("dog").click() cy.wait(500) - cy.addComponent("Form", "Field Group").then(fieldGroupId => { + cy.searchAndAddComponent("Field Group").then(fieldGroupId => { cy.contains("Update form fields").click() cy.get(".spectrum-Modal") .get(".confirm-wrap .spectrum-Button") @@ -88,7 +88,7 @@ filterTests(["all"], () => { }) it("deletes a component", () => { - cy.addComponent("Elements", "Paragraph").then(componentId => { + cy.searchAndAddComponent("Paragraph").then(componentId => { cy.get("[data-cy=setting-_instanceName] input").type(componentId).blur() cy.get( ".nav-items-container .nav-item.selected .actions > div > .icon" @@ -104,7 +104,7 @@ filterTests(["all"], () => { }) it("should clear the iframe place holder when a form field has been set", () => { - cy.addComponent("Form", "Form").then(formId => { + cy.searchAndAddComponent("Form").then(formId => { //For deletion cy.get("[data-cy=setting-_instanceName] input") .clear() @@ -123,10 +123,7 @@ filterTests(["all"], () => { const testFieldFocusOnCreate = componentLabel => { cy.log("Adding: " + componentLabel) - return cy.addComponent("Form", componentLabel).then(componentId => { - cy.getComponent(componentId) - .find(".component-placeholder") - .should("exist") + return cy.searchAndAddComponent(componentLabel).then(componentId => { cy.get("[data-cy=setting-field] button.spectrum-Picker").click() //Click the first appropriate field. They are filtered by type @@ -157,7 +154,7 @@ filterTests(["all"], () => { }) it("should populate the provider for charts with a data provider in its path", () => { - cy.addComponent("Data", "Data Provider").then(providerId => { + cy.searchAndAddComponent("Data Provider").then(providerId => { //For deletion cy.get("[data-cy=setting-_instanceName] input") .clear() @@ -181,7 +178,7 @@ filterTests(["all"], () => { const testFocusOnCreate = chartLabel => { cy.log("Adding: " + chartLabel) - cy.addComponent("Chart", chartLabel).then(componentId => { + cy.searchAndAddComponent(chartLabel).then(componentId => { cy.get( "[data-cy=dataProvider-prop-control] .spectrum-Picker" ).should("not.have.class", "is-focused") @@ -207,7 +204,7 @@ filterTests(["all"], () => { }) it("should replace the placeholder when a url is set on an image", () => { - cy.addComponent("Elements", "Image").then(imageId => { + cy.searchAndAddComponent("Image").then(imageId => { cy.get("[data-cy=setting-_instanceName] input") .clear() .type(imageId) @@ -229,7 +226,7 @@ filterTests(["all"], () => { }) it("should add a markdown component.", () => { - cy.addComponent("Elements", "Markdown Viewer").then(markdownId => { + cy.searchAndAddComponent("Markdown Viewer").then(markdownId => { cy.get("[data-cy=setting-_instanceName] input") .clear() .type(markdownId) @@ -253,8 +250,7 @@ filterTests(["all"], () => { }) it("should direct the user when adding an Icon component.", () => { - cy.addComponent("Elements", "Icon").then(iconId => { - cy.getComponent(iconId).find(".component-placeholder").should("exist") + cy.searchAndAddComponent("Icon").then(iconId => { cy.get("[data-cy=setting-_instanceName] input") .clear() .type(iconId) diff --git a/packages/builder/cypress/integration/createScreen.spec.js b/packages/builder/cypress/integration/createScreen.spec.js index 94a827f26f..a516e279f4 100644 --- a/packages/builder/cypress/integration/createScreen.spec.js +++ b/packages/builder/cypress/integration/createScreen.spec.js @@ -1,4 +1,5 @@ import filterTests from "../support/filterTests" +const interact = require('../support/interact') filterTests(["smoke", "all"], () => { context("Screen Tests", () => { @@ -10,32 +11,44 @@ filterTests(["smoke", "all"], () => { it("Should successfully create a screen", () => { cy.createScreen("test") - cy.get(".nav-items-container").within(() => { + cy.get(interact.BODY).within(() => { cy.contains("/test").should("exist") }) }) it("Should update the url", () => { cy.createScreen("test with spaces") - cy.get(".nav-items-container").within(() => { + cy.get(interact.BODY).within(() => { cy.contains("/test-with-spaces").should("exist") }) }) - it("Should create a blank screen with the selected access level", () => { - cy.createScreen("admin only", "Admin") + it("should delete all screens then create first screen via button", () => { + cy.deleteAllScreens() + + cy.contains("Create first screen").click() + cy.get(interact.BODY, { timeout: 2000 }).should('contain', '/home') + }) - cy.get(".nav-items-container").within(() => { - cy.contains("/admin-only").should("exist") - }) + it("Should create and filter screens by access level", () => { + const accessLevels = ["Basic", "Admin", "Public", "Power"] - cy.createScreen("open to all", "Public") + for (const access of accessLevels){ + // Create screen with specified access level + cy.createScreen(access, access) + // Filter by access level and confirm screen visible + cy.filterScreensAccessLevel(access) + cy.get(interact.BODY).within(() => { + cy.get(interact.NAV_ITEM).should('contain', access.toLowerCase()) + }) + } - cy.get(".nav-items-container").within(() => { - cy.contains("/open-to-all").should("exist") - //The access level should now be set to admin. Previous screens should be filtered. - cy.get(".nav-item").contains("/test-screen").should("not.exist") - }) + // Filter by All screens - Confirm all screens visible + cy.filterScreensAccessLevel("All screens") + cy.get(interact.BODY).should('contain', accessLevels[0]) + .and('contain', accessLevels[1]) + .and('contain', accessLevels[2]) + .and('contain', accessLevels[3]) }) }) }) diff --git a/packages/builder/cypress/integration/datasources/mySql.spec.js b/packages/builder/cypress/integration/datasources/mySql.spec.js index 4c24ea9280..86b255ff58 100644 --- a/packages/builder/cypress/integration/datasources/mySql.spec.js +++ b/packages/builder/cypress/integration/datasources/mySql.spec.js @@ -199,15 +199,16 @@ filterTests(["all"], () => { .within(() => { cy.get("input").clear().type(queryRename) }) - // Save query - cy.get(".spectrum-Button").contains("Save Query").click({ force: true }) + // Click on a nav item + cy.get(".nav-item").first().click() + // Confirm name change cy.get(".nav-item").should("contain", queryRename) }) it("should delete a query", () => { // Get query nav item - QueryName cy.get(".nav-item") - .contains(queryName) + .contains(queryRename) .parent() .within(() => { cy.get(".spectrum-Icon").eq(1).click({ force: true }) @@ -218,7 +219,7 @@ filterTests(["all"], () => { .contains("Delete Query") .click({ force: true }) // Confirm deletion - cy.get(".nav-item", { timeout: 1000 }).should("not.contain", queryName) + cy.get(".nav-item", { timeout: 1000 }).should("not.contain", queryRename) }) } }) diff --git a/packages/builder/cypress/integration/datasources/postgreSql.spec.js b/packages/builder/cypress/integration/datasources/postgreSql.spec.js index ccecfbd5df..feb583c83e 100644 --- a/packages/builder/cypress/integration/datasources/postgreSql.spec.js +++ b/packages/builder/cypress/integration/datasources/postgreSql.spec.js @@ -108,7 +108,7 @@ filterTests(["all"], () => { }) it("should delete a relationship", () => { - cy.get(".hierarchy-items-container").contains("PostgreSQL").click() + cy.get(".hierarchy-items-container").contains("PostgreSQL").click({ force: true }) cy.reload() // Delete one relationship cy.get(".spectrum-Table") @@ -150,13 +150,15 @@ filterTests(["all"], () => { cy.get("@query").its("response.statusCode").should("eq", 200) cy.get("@query").its("response.body").should("not.be.empty") // Save query + cy.intercept("**/queries").as("saveQuery") cy.get(".spectrum-Button").contains("Save Query").click({ force: true }) + cy.wait("@saveQuery") cy.get(".spectrum-Tabs-content", { timeout: 2000 }).should("contain", queryName) }) it("should switch to schema with no tables", () => { // Switch Schema - To one without any tables - cy.get(".hierarchy-items-container").contains("PostgreSQL").click() + cy.get(".hierarchy-items-container").contains("PostgreSQL").click({ force: true }) switchSchema("randomText") // No tables displayed @@ -218,8 +220,9 @@ filterTests(["all"], () => { it("should edit a query name", () => { // Access query cy.get(".hierarchy-items-container", { timeout: 2000 }) - .contains(queryName + " (1)") - .click() + //.contains(queryName + " (1)") + .contains(queryName) + .click({ force: true }) // Rename query cy.wait(1000) @@ -229,18 +232,16 @@ filterTests(["all"], () => { cy.get("input").clear().type(queryRename) }) - // Run and Save query - cy.get(".spectrum-Button", { timeout: 2000 }).contains("Run Query").click({ force: true }) - cy.wait(1000) - cy.get(".spectrum-Button", { timeout: 2000 }).contains("Save Query").click({ force: true }) - cy.reload({ timeout: 5000 }) - cy.get(".nav-item", { timeout: 2000 }).should("contain", queryRename) + // Click on a nav item and confirm name change + cy.get(".nav-item").first().click() + // Confirm name change + cy.get(".nav-item").should("contain", queryRename) }) it("should delete a query", () => { // Get query nav item - QueryName cy.get(".nav-item") - .contains(queryName) + .contains(queryRename) .parent() .within(() => { cy.get(".spectrum-Icon").eq(1).click({ force: true }) @@ -252,7 +253,7 @@ filterTests(["all"], () => { .click({ force: true }) // Confirm deletion cy.reload({ timeout: 5000 }) - cy.get(".nav-item", { timeout: 1000 }).should("not.contain", queryName) + cy.get(".nav-item", { timeout: 1000 }).should("not.contain", queryRename) }) const switchSchema = schema => { diff --git a/packages/builder/cypress/integration/revertApp.spec.js b/packages/builder/cypress/integration/revertApp.spec.js index 4c6f245b76..9a3d17f7c3 100644 --- a/packages/builder/cypress/integration/revertApp.spec.js +++ b/packages/builder/cypress/integration/revertApp.spec.js @@ -15,7 +15,7 @@ filterTests(['smoke', 'all'], () => { }) cy.get(interact.SPECTRUM_MODAL).within(() => { // Enter app name before revert - cy.get("input").type("Cypress Tests") + cy.get(interact.SPECTRUM_TEXTFIELD_INPUT).type("Cypress Tests") cy.intercept('**/revert').as('revertApp') // Click Revert cy.get(interact.SPECTRUM_BUTTON).contains("Revert").click({ force: true }) @@ -30,7 +30,7 @@ filterTests(['smoke', 'all'], () => { cy.navigateToFrontend() // Add initial component - Paragraph - cy.addComponent("Elements", "Paragraph") + cy.searchAndAddComponent("Paragraph") // Publish app cy.get(interact.SPECTRUM_BUTTON).contains("Publish").click({ force: true }) cy.get(interact.SPECTRUM_BUTTON_GROUP).within(() => { @@ -42,7 +42,7 @@ filterTests(['smoke', 'all'], () => { }) // Add second component - Button - cy.addComponent("Elements", "Button") + cy.searchAndAddComponent("Button") // Click Revert cy.get(interact.TOP_RIGHT_NAV).within(() => { cy.get(interact.AREA_LABEL_REVERT).click({ force: true }) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index b2ab8e678c..7efd32d258 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -4,31 +4,32 @@ Cypress.on("uncaught:exception", () => { // ACCOUNTS & USERS Cypress.Commands.add("login", (email, password) => { - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.wait(2000) - cy.url().then(url => { - if (url.includes("builder/admin")) { - // create admin user - cy.get("input").first().type("test@test.com") - cy.get('input[type="password"]').first().type("test") - cy.get('input[type="password"]').eq(1).type("test") - cy.contains("Create super admin user").click({ force: true }) - } - if (url.includes("builder/auth/login") || url.includes("builder/admin")) { - // login - cy.contains("Sign in to Budibase").then(() => { - if (email == null) { - cy.get("input").first().type("test@test.com") - cy.get('input[type="password"]').type("test") - } else { - cy.get("input").first().type(email) - cy.get('input[type="password"]').type(password) - } - cy.get("button").first().click({ force: true }) - cy.wait(1000) - }) - } - }) + cy.visit(`${Cypress.config().baseUrl}/builder`, { timeout: 10000 }) + cy.url() + .should("include", "/builder/") + .then(url => { + if (url.includes("builder/admin")) { + // create admin user + cy.get("input").first().type("test@test.com") + cy.get('input[type="password"]').first().type("test") + cy.get('input[type="password"]').eq(1).type("test") + cy.contains("Create super admin user").click({ force: true }) + } + if (url.includes("builder/auth") || url.includes("builder/admin")) { + // login + cy.contains("Sign in to Budibase").then(() => { + if (email == null) { + cy.get("input").first().type("test@test.com") + cy.get('input[type="password"]').type("test") + } else { + cy.get("input").first().type(email) + cy.get('input[type="password"]').type(password) + } + cy.get("button").first().click({ force: true }) + cy.wait(1000) + }) + } + }) }) Cypress.Commands.add("logOut", () => { @@ -50,23 +51,36 @@ Cypress.Commands.add("logoutNoAppGrid", () => { cy.wait(2000) }) -Cypress.Commands.add("createUser", email => { - // quick hacky recorded way to create a user +Cypress.Commands.add("createUser", (email, permission) => { cy.contains("Users").click() cy.get(`[data-cy="add-user"]`).click() cy.get(".spectrum-Dialog-grid").within(() => { - cy.get(".spectrum-Picker-label").click() - cy.get( - ".spectrum-Menu-item:nth-child(2) > .spectrum-Menu-itemLabel" - ).click() + // Enter email + cy.get(".spectrum-Textfield-input").clear().click().type(email) - // Onboarding type selector - cy.get(".spectrum-Textfield-input") - .eq(0) - .first() - .type(email, { force: true }) - cy.get(".spectrum-Button--cta").click({ force: true }) + // Select permission, if applicable + // Default is App User + if (permission != null) { + cy.get(".spectrum-Picker-label").click() + cy.get(".spectrum-Menu").within(() => { + cy.get(".spectrum-Menu-item") + .contains(permission) + .click({ force: true }) + }) + } + // Add user and wait for modal to change + cy.get(".spectrum-Button").contains("Add user").click({ force: true }) + cy.get(".spectrum-ActionButton").contains("Add email").should("not.exist") }) + // Onboarding modal + cy.get(".spectrum-Dialog-grid").within(() => { + cy.get(".onboarding-type").eq(1).click() + cy.get(".spectrum-Button").contains("Done").click({ force: true }) + cy.get(".spectrum-Button").contains("Cancel").should("not.exist") + }) + + // Accounts created modal - Click Done button + cy.get(".spectrum-Button").contains("Done").click({ force: true }) }) Cypress.Commands.add("deleteUser", email => { @@ -74,18 +88,13 @@ Cypress.Commands.add("deleteUser", email => { cy.contains("Users", { timeout: 2000 }).click() cy.contains(email).click() - // Click Delete user button - cy.get(".spectrum-Button") - .contains("Delete user") - .click({ force: true }) - .then(() => { - // Confirm deletion within modal - cy.get(".spectrum-Dialog-grid", { timeout: 500 }).within(() => { - cy.get(".spectrum-Button") - .contains("Delete user") - .click({ force: true }) - }) - }) + cy.get(".title").within(() => { + cy.get(".spectrum-Icon").click({ force: true }) + }) + cy.get(".spectrum-Menu").within(() => { + cy.get(".spectrum-Menu-item").contains("Delete").click({ force: true }) + }) + cy.get(".spectrum-Dialog-grid").contains("Delete user").click({ force: true }) }) Cypress.Commands.add("updateUserInformation", (firstName, lastName) => { @@ -120,9 +129,27 @@ Cypress.Commands.add("updateUserInformation", (firstName, lastName) => { .blur() } cy.get("button").contains("Update information").click({ force: true }) + cy.get(".spectrum-Dialog-grid").should("not.exist") }) }) +Cypress.Commands.add("setUserRole", (user, role) => { + cy.contains("Users").click() + cy.contains(user).click() + + // Set Role + cy.wait(500) + cy.get(".spectrum-Form-itemField") + .eq(2) + .within(() => { + cy.get(".spectrum-Picker-label").click({ force: true }) + }) + cy.get(".spectrum-Menu").within(() => { + cy.get(".spectrum-Menu-itemLabel").contains(role).click({ force: true }) + }) + cy.get(".spectrum-Form-itemField").eq(2).should("contain", role) +}) + // APPLICATIONS Cypress.Commands.add("createTestApp", () => { const appName = "Cypress Tests" @@ -139,7 +166,9 @@ Cypress.Commands.add("createApp", (name, addDefaultTable) => { cy.get(`[data-cy="create-app-btn"]`, { timeout: 5000 }).click({ force: true }) // If apps already exist - cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`, { + timeout: 5000, + }) .its("body") .then(val => { if (val.length > 0) { @@ -208,7 +237,7 @@ Cypress.Commands.add("deleteApp", name => { cy.get(".app-overview-actions-icon").within(() => { cy.get(".spectrum-Icon").click({ force: true }) }) - cy.get(".spectrum-Menu").contains("Delete").click() + cy.get(".spectrum-Menu").contains("Delete").click({ force: true }) cy.get(".spectrum-Dialog-grid").within(() => { cy.get("input").type(name) }) @@ -223,9 +252,11 @@ Cypress.Commands.add("deleteApp", name => { }) Cypress.Commands.add("deleteAllApps", () => { - cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.visit(`${Cypress.config().baseUrl}/builder`, { timeout: 5000 }) cy.wait(500) - cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`, { + timeout: 5000, + }) .its("body") .then(val => { for (let i = 0; i < val.length; i++) { @@ -285,7 +316,7 @@ Cypress.Commands.add("updateAppName", (changedName, noName) => { }) Cypress.Commands.add("publishApp", resolvedAppPath => { - //Assumes you have navigated to an application first + // Assumes you have navigated to an application first cy.get(".toprightnav button.spectrum-Button") .contains("Publish") .click({ force: true }) @@ -297,7 +328,7 @@ Cypress.Commands.add("publishApp", resolvedAppPath => { cy.wait(1000) }) - //Verify that the app url is presented correctly to the user + // Verify that the app url is presented correctly to the user cy.get(".spectrum-Modal [data-cy='deploy-app-success-modal']") .should("be.visible") .within(() => { @@ -377,7 +408,7 @@ Cypress.Commands.add("searchForApplication", appName => { // Assumes there are no others Cypress.Commands.add("applicationInAppTable", appName => { cy.visit(`${Cypress.config().baseUrl}/builder`, { timeout: 10000 }) - cy.get(".appTable", { timeout: 2000 }).within(() => { + cy.get(".appTable", { timeout: 5000 }).within(() => { cy.get(".title").contains(appName).should("exist") }) }) @@ -418,7 +449,12 @@ Cypress.Commands.add("createTable", (tableName, initialTable) => { cy.get("input", { timeout: 2000 }).first().type(tableName).blur() cy.get(".spectrum-ButtonGroup").contains("Create").click() }) - cy.contains(tableName).should("be.visible") + // Ensure modal has closed and table is created + cy.get(".spectrum-Modal").should("not.exist") + cy.get(".spectrum-Tabs-content", { timeout: 1000 }).should( + "contain", + tableName + ) }) Cypress.Commands.add("createTestTableWithData", () => { @@ -487,26 +523,52 @@ Cypress.Commands.add("selectTable", tableName => { }) Cypress.Commands.add("addCustomSourceOptions", totalOptions => { - cy.get(".spectrum-ActionButton") - .contains("Define Options") - .click() - .then(() => { - for (let i = 0; i < totalOptions; i++) { - // Add radio button options - cy.get(".spectrum-Button") - .contains("Add Option") - .click({ force: true }) - .then(() => { - cy.get("[placeholder='Label']", { timeout: 500 }).eq(i).type(i) - cy.get("[placeholder='Value']").eq(i).type(i) - }) - } - // Save options - cy.get(".spectrum-Button").contains("Save").click({ force: true }) - }) + cy.get('[data-cy="customOptions-prop-control"]').within(() => { + cy.get(".spectrum-ActionButton-label").click({ force: true }) + }) + for (let i = 0; i < totalOptions; i++) { + // Add radio button options + cy.get(".spectrum-Button-label", { timeout: 1000 }) + .contains("Add Option") + .click({ force: true }) + .then(() => { + cy.get("[placeholder='Label']", { timeout: 500 }).eq(i).type(i) + cy.get("[placeholder='Value']").eq(i).type(i) + }) + } + // Save options + cy.get(".spectrum-Button").contains("Save").click({ force: true }) +}) + +// DESIGN SECTION +Cypress.Commands.add("searchAndAddComponent", component => { + // Open component menu + cy.get(".icon-side-nav").within(() => { + cy.get(".icon-side-nav-item").eq(1).click() + }) + cy.get(".add-component > .spectrum-Button") + .contains("Add component") + .click({ force: true }) + cy.get(".container", { timeout: 1000 }).within(() => { + cy.get(".title").should("contain", "Add component") + + // Search and add component + cy.get(".spectrum-Textfield-input").clear().type(component) + cy.get(".body").within(() => { + cy.get(".component") + .contains(new RegExp("^" + component + "$"), { timeout: 3000 }) + .click({ force: true }) + }) + }) + cy.wait(1000) + cy.location().then(loc => { + const params = loc.pathname.split("/") + const componentId = params[params.length - 1] + cy.getComponent(componentId, { timeout: 3000 }).should("exist") + return cy.wrap(componentId) + }) }) -// DESIGN AREA Cypress.Commands.add("addComponent", (category, component) => { if (category) { cy.get(`[data-cy="category-${category}"]`, { timeout: 3000 }).click({ @@ -542,7 +604,7 @@ Cypress.Commands.add("getComponent", componentId => { Cypress.Commands.add("createScreen", (route, accessLevelLabel) => { // Blank Screen cy.contains("Design").click() - cy.get("[aria-label=AddCircle]").click() + cy.get(".spectrum-Button").contains("Add screen").click({ force: true }) cy.get(".spectrum-Modal").within(() => { cy.get("[data-cy='blank-screen']").click() cy.get(".spectrum-Button").contains("Continue").click({ force: true }) @@ -567,7 +629,7 @@ Cypress.Commands.add( "createDatasourceScreen", (datasourceNames, accessLevelLabel) => { cy.contains("Design").click() - cy.get("[aria-label=AddCircle]").click() + cy.get(".spectrum-Button").contains("Add screen").click({ force: true }) cy.get(".spectrum-Modal").within(() => { cy.get(".item").contains("Autogenerated screens").click() cy.get(".spectrum-Button").contains("Continue").click({ force: true }) @@ -622,13 +684,60 @@ Cypress.Commands.add( } ) +Cypress.Commands.add("filterScreensAccessLevel", accessLevel => { + // Filters screens by access level dropdown + cy.get(".body").within(() => { + cy.get(".spectrum-Form-item").eq(1).click() + }) + cy.get(".spectrum-Menu").within(() => { + cy.contains(accessLevel).click() + }) +}) + +Cypress.Commands.add("deleteScreen", screen => { + // Navigates to Design section and deletes specified screen + cy.contains("Design").click() + cy.get(".body").within(() => { + cy.contains(screen) + .siblings(".actions") + .within(() => { + cy.get(".spectrum-Icon").click({ force: true }) + }) + }) + cy.get(".spectrum-Menu > .spectrum-Menu-item > .spectrum-Menu-itemLabel") + .contains("Delete") + .click() + + cy.get( + ".spectrum-Dialog-grid > .spectrum-ButtonGroup > .confirm-wrap > .spectrum-Button" + ).click({ force: true }) + cy.get(".spectrum-Dialog-grid", { timeout: 10000 }).should("not.exist") +}) + +Cypress.Commands.add("deleteAllScreens", () => { + // Deletes all screens + cy.get(".body") + .find(".nav-item") + .its("length") + .then(len => { + for (let i = 0; i < len; i++) { + cy.get(".body > .nav-item") + .eq(0) + .invoke("text") + .then(text => { + cy.deleteScreen(text.trim()) + }) + } + }) +}) + // NAVIGATION Cypress.Commands.add("navigateToFrontend", () => { // Clicks on Design tab and then the Home nav item cy.wait(500) cy.contains("Design").click() cy.get(".spectrum-Search", { timeout: 2000 }).type("/") - cy.get(".nav-item", { timeout: 2000 }).contains("home").click() + cy.get(".nav-item", { timeout: 2000 }).contains("home").click({ force: true }) }) Cypress.Commands.add("navigateToDataSection", () => { @@ -640,9 +749,11 @@ Cypress.Commands.add("navigateToDataSection", () => { Cypress.Commands.add("navigateToAutogeneratedModal", () => { // Screen name must already exist within data source cy.contains("Design").click() - cy.get("[aria-label=AddCircle]").click() + cy.get(".spectrum-Button").contains("Add screen").click({ force: true }) cy.get(".spectrum-Modal").within(() => { - cy.get(".item").contains("Autogenerated screens").click() + cy.get(".item", { timeout: 2000 }) + .contains("Autogenerated screens") + .click({ force: true }) cy.get(".spectrum-Button").contains("Continue").click({ force: true }) cy.wait(500) }) diff --git a/packages/builder/cypress/support/interact.js b/packages/builder/cypress/support/interact.js index 0b31d8a8c5..4f2451ce4b 100644 --- a/packages/builder/cypress/support/interact.js +++ b/packages/builder/cypress/support/interact.js @@ -12,7 +12,7 @@ export const APP_NAME_INPUT = "input" // we need to update this with atribute cy export const SPECTRUM_BUTTON_GROUP = ".spectrum-ButtonGroup" export const SPECTRUM_MODAL_INPUT = ".spectrum-Modal input" -//AddMultiOptionDatatype test +//AddMultiOptionDatatype export const CATEGORY_DATA = '[data-cy="category-Data"]' export const COMPONENT_DATA_PROVIDER = '[data-cy="component-Data Provider"]' export const DATASOURCE_PROP_CONTROL = '[data-cy="dataSource-prop-control"]' @@ -51,7 +51,7 @@ export const LABEL_ADD_CIRCLE = "[aria-label=AddCircle]" export const ITEM_DISABLED = ".item.disabled" export const CONFIRM_WRAP_SPE_BUTTON = ".confirm-wrap .spectrum-Button" export const DATA_SOURCE_ENTRY = ".data-source-entry" -export const NAV_ITEMS_CONTAINER = ".nav-items-container" +export const BODY = ".body" //publishWorkFlow export const DEPLOY_APP_MODAL = ".spectrum-Modal [data-cy=deploy-app-modal]" @@ -108,6 +108,9 @@ export const CONTAINER = ".container" export const REGENERATE = ".regenerate" export const SPECTRUM_DIALOG_CONTENT = ".spectrum-Dialog-content" export const SPECTRUM_ICON = ".spectrum-Icon" +export const SPECTRUM_HEADING = ".spectrum-Heading" +export const SPECTRUM_FORM_ITEMFIELD = ".spectrum-Form-itemField" +export const LIST_ITEMS = ".list-items" //createView export const SPECTRUM_MENU_ITEM_LABEL = ".spectrum-Menu-itemLabel" diff --git a/packages/builder/package.json b/packages/builder/package.json index ca951b0891..4e4089ebe5 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "license": "GPL-3.0", "private": true, "scripts": { @@ -69,10 +69,10 @@ } }, "dependencies": { - "@budibase/bbui": "^1.1.31", - "@budibase/client": "^1.1.31", - "@budibase/frontend-core": "^1.1.31", - "@budibase/string-templates": "^1.1.31", + "@budibase/bbui": "1.1.33-alpha.0", + "@budibase/client": "1.1.33-alpha.0", + "@budibase/frontend-core": "1.1.33-alpha.0", + "@budibase/string-templates": "1.1.33-alpha.0", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js index dd09e3356a..af102ab694 100644 --- a/packages/builder/src/builderStore/store/automation/index.js +++ b/packages/builder/src/builderStore/store/automation/index.js @@ -68,7 +68,19 @@ const automationActions = store => ({ return state }) }, - + duplicate: async automation => { + const response = await API.createAutomation({ + ...automation, + name: `${automation.name} - copy`, + _id: undefined, + _ref: undefined, + }) + store.update(state => { + state.automations = [...state.automations, response.automation] + store.actions.select(response.automation) + return state + }) + }, save: async automation => { const response = await API.updateAutomation(automation) store.update(state => { diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte index 99c6f251f9..31df2585b8 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItemHeader.svelte @@ -32,7 +32,8 @@ if (!results) { return {} } - if (results.outputs?.status?.toLowerCase() === "stopped") { + const lcStatus = results.outputs?.status?.toLowerCase() + if (lcStatus === "stopped" || lcStatus === "stopped_error") { return { yellow: true, message: "Stopped" } } else if (results.outputs?.success || isTrigger) { return { positive: true, message: "Success" } diff --git a/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte b/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte index 0d858d7a19..30892882bf 100644 --- a/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte @@ -19,12 +19,23 @@ notifications.error("Error deleting automation") } } + + async function duplicateAutomation() { + try { + await automationStore.actions.duplicate(automation) + notifications.success("Automation has been duplicated successfully") + $goto(`./${$automationStore.selectedAutomation.automation._id}`) + } catch (error) { + notifications.error("Error duplicating automation") + } + }
+ Duplicate Edit Delete
diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index fd0b82a8a6..90e7ab661c 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -260,6 +260,7 @@ {bindings} allowJS={false} updateOnChange={false} + drawerLeft="260px" /> {/if} {:else if value.customType === "query"} @@ -357,6 +358,7 @@ {bindings} updateOnChange={false} placeholder={value.customType === "queryLimit" ? queryLimit : ""} + drawerLeft="260px" />
{/if} diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte index b754f878ce..f19f2279d9 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/rest/auth/RestAuthenticationModal.svelte @@ -211,7 +211,6 @@ bindings={getAuthBindings()} on:change={e => { form.bearer.token = e.detail - console.log(e.detail) onFieldChange() }} on:blur={() => { diff --git a/packages/builder/src/components/common/RoleSelect.svelte b/packages/builder/src/components/common/RoleSelect.svelte new file mode 100644 index 0000000000..a3f75fd4eb --- /dev/null +++ b/packages/builder/src/components/common/RoleSelect.svelte @@ -0,0 +1,24 @@ + + + - import { Layout, Icon, ActionButton } from "@budibase/bbui" + import { Layout, Icon, ActionButton, InlineAlert } from "@budibase/bbui" import StatusRenderer from "./StatusRenderer.svelte" import DateTimeRenderer from "components/common/renderers/DateTimeRenderer.svelte" import TestDisplay from "components/automation/AutomationBuilder/TestDisplay.svelte" @@ -9,6 +9,7 @@ export let history export let appId export let close + const STOPPED_ERROR = "stopped_error" $: exists = $automationStore.automations?.find( auto => auto._id === history?.automationId @@ -32,6 +33,15 @@
{history.automationName}
+ {#if history.status === STOPPED_ERROR} +
+ +
+ {/if}
{#if exists} diff --git a/packages/builder/src/components/portal/overview/automation/StatusRenderer.svelte b/packages/builder/src/components/portal/overview/automation/StatusRenderer.svelte index 5f71041809..a50932c582 100644 --- a/packages/builder/src/components/portal/overview/automation/StatusRenderer.svelte +++ b/packages/builder/src/components/portal/overview/automation/StatusRenderer.svelte @@ -3,7 +3,8 @@ export let value $: isError = !value || value.toLowerCase() === "error" - $: isStopped = value?.toLowerCase() === "stopped" + $: isStoppedError = value?.toLowerCase() === "stopped_error" + $: isStopped = value?.toLowerCase() === "stopped" || isStoppedError $: status = getStatus(isError, isStopped) function getStatus(error, stopped) { diff --git a/packages/builder/src/components/settings/UserGroupPicker.svelte b/packages/builder/src/components/settings/UserGroupPicker.svelte new file mode 100644 index 0000000000..6eef15efe6 --- /dev/null +++ b/packages/builder/src/components/settings/UserGroupPicker.svelte @@ -0,0 +1,75 @@ + + +
+ +
+
+ {filtered.length} {title}{filtered.length === 1 ? "" : "s"} +
+
+ Add all +
+
+ +
+ {#each filtered as item} +
{ + select(item._id) + }} + style="padding-bottom: var(--spacing-m)" + class="selection" + > +
+ {item[key]} +
+ + {#if selected.includes(item._id)} +
+ +
+ {/if} +
+ {/each} +
+
+ + diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 2cf1ce7f6c..23f9f3f80c 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -111,7 +111,6 @@ await admin.init() // Create user - await API.updateOwnMetadata({ roleId: $values.roleId }) await auth.setInitInfo({}) // Create a default home screen if no template was selected diff --git a/packages/builder/src/helpers/data/utils.js b/packages/builder/src/helpers/data/utils.js index 23aeb314a0..647c2be33e 100644 --- a/packages/builder/src/helpers/data/utils.js +++ b/packages/builder/src/helpers/data/utils.js @@ -150,12 +150,31 @@ export function flipHeaderState(headersActivity) { return enabled } +export const parseToCsv = (headers, rows) => { + let csv = headers?.map(key => `"${key}"`)?.join(",") || "" + + for (let row of rows) { + csv = `${csv}\n${headers + .map(header => { + let val = row[header] + val = + typeof val === "object" && !(val instanceof Date) + ? `"${JSON.stringify(val).replace(/"/g, "'")}"` + : `"${val}"` + return val.trim() + }) + .join(",")}` + } + return csv +} + export default { breakQueryString, buildQueryString, fieldsToSchema, flipHeaderState, keyValueToQueryParameters, + parseToCsv, queryParametersToKeyValue, schemaToFields, } diff --git a/packages/builder/src/helpers/featureFlags.js b/packages/builder/src/helpers/featureFlags.js index 9533abed7e..a0cda8d5fa 100644 --- a/packages/builder/src/helpers/featureFlags.js +++ b/packages/builder/src/helpers/featureFlags.js @@ -3,6 +3,7 @@ import { get } from "svelte/store" export const FEATURE_FLAGS = { LICENSING: "LICENSING", + USER_GROUPS: "USER_GROUPS", } export const isEnabled = featureFlag => { diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte index 6a798f0178..5ccc173318 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte @@ -440,6 +440,7 @@ ...dynamicRequestBindings, ...dataSourceStaticBindings, ]} + bindingDrawerLeft="260px" /> @@ -448,6 +449,7 @@ name="param" headings bindings={mergedBindings} + bindingDrawerLeft="260px" /> @@ -458,6 +460,7 @@ name="header" headings bindings={mergedBindings} + bindingDrawerLeft="260px" /> diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index 304d41ad19..3c99c90d49 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -186,7 +186,7 @@ $goto("./navigation") } } else if (type === "request-add-component") { - $goto("./components/new") + $goto(`./components/${$selectedComponent?._id}/new`) } else if (type === "highlight-setting") { store.actions.settings.highlight(data.setting) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte index 63a3888ecf..ab776dea5d 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte @@ -9,7 +9,7 @@ import { setContext } from "svelte" import DNDPositionIndicator from "./DNDPositionIndicator.svelte" import { DropPosition } from "./dndStore" - import { Button } from "@budibase/bbui" + import { notifications, Button } from "@budibase/bbui" let scrollRef @@ -56,6 +56,15 @@ }) } + const onDrop = async () => { + try { + await dndStore.actions.drop() + } catch (error) { + console.error(error) + notifications.error("Error saving component") + } + } + // Set scroll context so components can invoke scrolling when selected setContext("scroll", { scrollTo, @@ -81,6 +90,7 @@ opened scrollable icon="WebPage" + on:drop={onDrop} > diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUISection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUISection.svelte index ba84b67622..fca81f7652 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUISection.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUISection.svelte @@ -28,12 +28,15 @@ } drawer.hide() } + + $: conditionCount = componentInstance?._conditions?.length + $: conditionText = `${conditionCount || "No"} condition${ + conditionCount !== 1 ? "s" : "" + } set` - + +
{conditionText}
Configure conditions
@@ -45,3 +48,10 @@ + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/NewComponentPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/NewComponentPanel.svelte index 8c62750b95..df157ccf0f 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/NewComponentPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/NewComponentPanel.svelte @@ -184,6 +184,7 @@
{category.name}
{#each category.children as component}
app.status === AppStatus.DEPLOYED + $: userGroups = $groups.filter(group => + group.users.find(user => user._id === $auth.user?._id) + ) + let userApps = [] $: publishedApps = $apps.filter(publishedAppsOnly) - $: userApps = $auth.user?.builder?.global - ? publishedApps - : publishedApps.filter(app => - Object.keys($auth.user?.roles).includes(app.prodId) - ) + + $: { + if (!Object.keys($auth.user?.roles).length && $auth.user?.userGroups) { + userApps = + $auth.user?.builder?.global || $auth.user?.admin?.global + ? publishedApps + : publishedApps.filter(app => { + return userGroups.find(group => { + return Object.keys(group.roles) + .map(role => apps.extractAppId(role)) + .includes(app.appId) + }) + }) + } else { + userApps = + $auth.user?.builder?.global || $auth.user?.admin?.global + ? publishedApps + : publishedApps.filter(app => + Object.keys($auth.user?.roles) + .map(x => apps.extractAppId(x)) + .includes(app.appId) + ) + } + } function getUrl(app) { if (app.url) { diff --git a/packages/builder/src/pages/builder/portal/_layout.svelte b/packages/builder/src/pages/builder/portal/_layout.svelte index ae0362af72..21259c4d84 100644 --- a/packages/builder/src/pages/builder/portal/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/_layout.svelte @@ -45,6 +45,7 @@ }, ]) } + if (admin) { menu = menu.concat([ { @@ -65,6 +66,15 @@ }, ]) + if (isEnabled(FEATURE_FLAGS.USER_GROUPS)) { + let item = { + title: "User Groups", + href: "/builder/portal/manage/groups", + } + + menu.splice(2, 0, item) + } + if (!$adminStore.cloud) { menu = menu.concat([ { diff --git a/packages/builder/src/pages/builder/portal/apps/_components/AcessFilter.svelte b/packages/builder/src/pages/builder/portal/apps/_components/AcessFilter.svelte new file mode 100644 index 0000000000..d0662e7b41 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/apps/_components/AcessFilter.svelte @@ -0,0 +1,43 @@ + + + diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index de5ad178cb..0d05e170e0 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -20,12 +20,14 @@ import { store, automationStore } from "builderStore" import { API } from "api" import { onMount } from "svelte" - import { apps, auth, admin, templates } from "stores/portal" + import { apps, auth, admin, templates, groups } from "stores/portal" import download from "downloadjs" import { goto } from "@roxi/routify" import AppRow from "components/start/AppRow.svelte" import { AppStatus } from "constants" import Logo from "assets/bb-space-man.svg" + import AccessFilter from "./_components/AcessFilter.svelte" + import { Constants } from "@budibase/frontend-core" let sortBy = "name" let template @@ -39,6 +41,7 @@ let cloud = $admin.cloud let creatingFromTemplate = false let automationErrors + let accessFilterList = null const resolveWelcomeMessage = (auth, apps) => { const userWelcome = auth?.user?.firstName @@ -56,14 +59,20 @@ : "Start from scratch" $: enrichedApps = enrichApps($apps, $auth.user, sortBy) - $: filteredApps = enrichedApps.filter(app => - app?.name?.toLowerCase().includes(searchTerm.toLowerCase()) + $: filteredApps = enrichedApps.filter( + app => + app?.name?.toLowerCase().includes(searchTerm.toLowerCase()) && + (accessFilterList !== null ? accessFilterList.includes(app?.appId) : true) ) $: lockedApps = filteredApps.filter(app => app?.lockedYou || app?.lockedOther) $: unlocked = lockedApps?.length === 0 $: automationErrors = getAutomationErrors(enrichedApps) + $: hasGroupsLicense = $auth.user?.license.features.includes( + Constants.Features.USER_GROUPS + ) + const enrichApps = (apps, user, sortBy) => { const enrichedApps = apps.map(app => ({ ...app, @@ -202,6 +211,10 @@ $goto(`../../app/${app.devId}`) } + const accessFilterAction = accessFilter => { + accessFilterList = accessFilter.detail + } + function createAppFromTemplateUrl(templateKey) { // validate the template key just to make sure const templateParts = templateKey.split("/") @@ -347,6 +360,9 @@ {/if}
+ {#if hasGroupsLicense && $groups.length} + + {/if} + + + + diff --git a/packages/builder/src/pages/builder/portal/manage/groups/_components/UserGroupsRow.svelte b/packages/builder/src/pages/builder/portal/manage/groups/_components/UserGroupsRow.svelte new file mode 100644 index 0000000000..e00123614a --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/groups/_components/UserGroupsRow.svelte @@ -0,0 +1,129 @@ + + +
+
+
+
+ +
+
+
+ {group.name} +
+
+
+
+ +
+ {parseInt(group?.users?.length) || 0} user{parseInt( + group?.users?.length + ) === 1 + ? "" + : "s"} +
+
+
+ + +
+ {parseInt(group?.apps?.length) || 0} app{parseInt(group?.apps?.length) === 1 + ? "" + : "s"} +
+
+
+
+
+ +
+
+ + + + + deleteGroup(group)} icon="Delete" + >Delete + editGroup(group)} icon="Edit">Edit + +
+
+
+ + + + + + diff --git a/packages/builder/src/pages/builder/portal/manage/groups/_layout.svelte b/packages/builder/src/pages/builder/portal/manage/groups/_layout.svelte new file mode 100644 index 0000000000..a13211a9bb --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/groups/_layout.svelte @@ -0,0 +1,3 @@ +
+ +
diff --git a/packages/builder/src/pages/builder/portal/manage/groups/index.svelte b/packages/builder/src/pages/builder/portal/manage/groups/index.svelte new file mode 100644 index 0000000000..01bd8e889d --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/groups/index.svelte @@ -0,0 +1,153 @@ + + + + +
+ User groups + {#if !hasGroupsLicense} + +
+
+ Pro plan +
+
+
+ {/if} +
+ Easily assign and manage your users access with User Groups +
+
+ + {#if !hasGroupsLicense} + + {/if} +
+ + {#if hasGroupsLicense && $groups.length} +
+ {#each $groups as group} +
+ +
+ {/each} +
+ {/if} +
+ + + + + + diff --git a/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte b/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte index a8cb340465..3e7c64dbec 100644 --- a/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte @@ -2,79 +2,143 @@ import { goto } from "@roxi/routify" import { ActionButton, + ActionMenu, + Avatar, Button, Layout, Heading, Body, - Divider, Label, + List, + ListItem, + Icon, Input, + MenuItem, + Popover, Select, - Toggle, Modal, - Table, - ModalContent, notifications, + StatusLight, } from "@budibase/bbui" + import { onMount } from "svelte" import { fetchData } from "helpers" - import { users, auth } from "stores/portal" - - import TagsRenderer from "./_components/RolesTagsTableRenderer.svelte" - - import UpdateRolesModal from "./_components/UpdateRolesModal.svelte" + import { users, auth, groups, apps } from "stores/portal" + import { roles } from "stores/backend" + import { Constants } from "@budibase/frontend-core" import ForceResetPasswordModal from "./_components/ForceResetPasswordModal.svelte" + import { RoleUtils } from "@budibase/frontend-core" + import UserGroupPicker from "components/settings/UserGroupPicker.svelte" + import DeleteUserModal from "./_components/DeleteUserModal.svelte" export let userId - let deleteUserModal - let editRolesModal + + let deleteModal let resetPasswordModal + let popoverAnchor + let searchTerm = "" + let popover + let selectedGroups = [] + let allAppList = [] + let user + let loaded = false + $: fetchUser(userId) - const roleSchema = { - name: { displayName: "App" }, - role: {}, - } + $: fullName = $userFetch?.data?.firstName + ? $userFetch?.data?.firstName + " " + $userFetch?.data?.lastName + : "" - const noRoleSchema = { - name: { displayName: "App" }, - } + $: hasGroupsLicense = $auth.user?.license.features.includes( + Constants.Features.USER_GROUPS + ) + $: nameLabel = getNameLabel($userFetch) + $: initials = getInitials(nameLabel) - $: defaultRoleId = $userFetch?.data?.builder?.global ? "ADMIN" : "" - // Merge the Apps list and the roles response to get something that makes sense for the table - $: allAppList = Object.keys($apps?.data).map(id => { - const roleId = $userFetch?.data?.roles?.[id] || defaultRoleId - const role = $apps?.data?.[id].roles.find(role => role._id === roleId) - return { - ...$apps?.data?.[id], - _id: id, - role: [role], - } + $: allAppList = $apps + .filter(x => { + if ($userFetch.data?.roles) { + return Object.keys($userFetch.data.roles).find(y => { + return x.appId === apps.extractAppId(y) + }) + } + }) + .map(app => { + let roles = Object.fromEntries( + Object.entries($userFetch.data.roles).filter(([key]) => { + return apps.extractAppId(key) === app.appId + }) + ) + return { + name: app.name, + devId: app.devId, + icon: app.icon, + roles, + } + }) + // Used for searching through groups in the add group popover + $: filteredGroups = $groups.filter( + group => + selectedGroups && + group?.name?.toLowerCase().includes(searchTerm.toLowerCase()) + ) + $: userGroups = $groups.filter(x => { + return x.users?.find(y => { + return y._id === userId + }) }) - $: appList = allAppList.filter(app => !!app.role[0]) - $: noRoleAppList = allAppList - .filter(app => !app.role[0]) - .map(app => { - delete app.role - return app - }) - - let selectedApp + $: globalRole = $userFetch?.data?.admin?.global + ? "admin" + : $userFetch?.data?.builder?.global + ? "developer" + : "appUser" const userFetch = fetchData(`/api/global/users/${userId}`) - const apps = fetchData(`/api/global/roles`) - async function deleteUser() { - try { - await users.delete(userId) - notifications.success(`User ${$userFetch?.data?.email} deleted.`) - $goto("./") - } catch (error) { - notifications.error("Error deleting user") + const getNameLabel = userFetch => { + const { firstName, lastName, email } = userFetch?.data || {} + if (!firstName && !lastName) { + return email || "" } + let label + if (firstName) { + label = firstName + if (lastName) { + label += ` ${lastName}` + } + } else { + label = lastName + } + return label } - let toggleDisabled = false + const getInitials = nameLabel => { + if (!nameLabel) { + return "?" + } + return nameLabel + .split(" ") + .slice(0, 2) + .map(x => x[0]) + .join("") + } + const getRoleLabel = roleId => { + const role = $roles.find(x => x._id === roleId) + return role?.name || "Custom role" + } + + function getHighestRole(roles) { + let highestRole + let highestRoleNumber = 0 + Object.keys(roles).forEach(role => { + let roleNumber = RoleUtils.getRolePriority(roles[role]) + if (roleNumber > highestRoleNumber) { + highestRoleNumber = roleNumber + highestRole = roles[role] + } + }) + return highestRole + } async function updateUserFirstName(evt) { try { await users.save({ ...$userFetch?.data, firstName: evt.target.value }) @@ -84,6 +148,13 @@ } } + async function removeGroup(id) { + let updatedGroup = $groups.find(x => x._id === id) + let newUsers = updatedGroup.users.filter(user => user._id !== userId) + updatedGroup.users = newUsers + groups.actions.save(updatedGroup) + } + async function updateUserLastName(evt) { try { await users.save({ ...$userFetch?.data, lastName: evt.target.value }) @@ -93,167 +164,214 @@ } } - async function toggleFlag(flagName, detail) { - toggleDisabled = true + async function updateUserRole({ detail }) { + if (detail === "developer") { + toggleFlags({ admin: { global: false }, builder: { global: true } }) + } else if (detail === "admin") { + toggleFlags({ admin: { global: true }, builder: { global: true } }) + } else if (detail === "appUser") { + toggleFlags({ admin: { global: false }, builder: { global: false } }) + } + } + + async function addGroup(groupId) { + let selectedGroup = selectedGroups.includes(groupId) + let group = $groups.find(group => group._id === groupId) + + if (selectedGroup) { + selectedGroups = selectedGroups.filter(id => id === selectedGroup) + let newUsers = group.users.filter(groupUser => user._id !== groupUser._id) + group.users = newUsers + } else { + selectedGroups = [...selectedGroups, groupId] + group.users.push(user) + } + + await groups.actions.save(group) + } + + async function fetchUser(userId) { + let userPromise = users.get(userId) + user = await userPromise + } + + async function toggleFlags(detail) { try { - await users.save({ ...$userFetch?.data, [flagName]: { global: detail } }) + await users.save({ ...$userFetch?.data, ...detail }) await userFetch.refresh() } catch (error) { notifications.error("Error updating user") } - toggleDisabled = false } - async function toggleBuilderAccess({ detail }) { - return toggleFlag("builder", detail) - } - - async function toggleAdminAccess({ detail }) { - return toggleFlag("admin", detail) - } - - async function openUpdateRolesModal({ detail }) { - selectedApp = detail - editRolesModal.show() - } + function addAll() {} + onMount(async () => { + try { + await Promise.all([groups.actions.init(), apps.load(), roles.fetch()]) + loaded = true + } catch (error) { + notifications.error("Error getting user groups") + } + }) - - -
- $goto("./")} - quiet - size="S" - icon="BackAndroid" - > - Back to users - -
- User: {$userFetch?.data?.email} - - Change user settings and update their app roles. Also contains the ability - to delete the user as well as force reset their password. - -
- - - General -
-
- - +{#if loaded} + + +
+ $goto("./")} size="S" icon="ArrowLeft"> + Back +
-
- - -
-
- - -
- - {#if userId !== $auth.user._id} +
+ +
- - First name +
- - Last name +
- {/if} -
-
- Force password reset -
-
- - - Configure roles - Specify a role to grant access to an app. - - - - No Access - Apps do not appear in the users portal. Public pages may still be viewed - if visited directly. -
- - - - Delete user - Deleting a user completely removes them from your account. - -
- -
- + + {#if userId !== $auth.user._id} +
+ + + + - + {#each userData as input, index} +
+
+ +
+
+ removeInput(index)} + /> +
+
+ {/each} +
+ Add email +
+
- {#if basic} - + {#if hasGroupsLicense} + option.name} + getOptionValue={option => option._id} + /> {/if} - -
-
- - -
-
- - -
-
diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/AppsTableRenderer.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/AppsTableRenderer.svelte new file mode 100644 index 0000000000..d348082ffa --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/AppsTableRenderer.svelte @@ -0,0 +1,22 @@ + + +
+
+ +
+ {parseInt(value?.length) || 0} +
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/DeleteUserModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/DeleteUserModal.svelte new file mode 100644 index 0000000000..946fa430d2 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/DeleteUserModal.svelte @@ -0,0 +1,31 @@ + + + + + Are you sure you want to delete {user?.email} + + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/EmailSelect.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/EmailSelect.svelte new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/GroupsTableRenderer.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/GroupsTableRenderer.svelte new file mode 100644 index 0000000000..772b5fe7b9 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/GroupsTableRenderer.svelte @@ -0,0 +1,36 @@ + + +
+
+ +
+ {#if value?.length === 0} +
0
+ {:else if value?.length === 1} +
+ {value[0]?.name} +
+ {:else} +
+ {parseInt(value?.length) || 0} groups +
+ {/if} +
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/ImportUsersModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/ImportUsersModal.svelte new file mode 100644 index 0000000000..bc8a0d1f1f --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/ImportUsersModal.svelte @@ -0,0 +1,153 @@ + + + createUsersFromCsv({ userEmails, usersRole, userGroups })} + disabled={!userEmails.length || !validEmails(userEmails) || !usersRole} +> + Import your users email addrresses from a CSV + +
+ + +
+ + + + {#if hasGroupsLicense} + option.name} + getOptionValue={option => option._id} + /> + {/if} +
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/NameTableRenderer.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/NameTableRenderer.svelte new file mode 100644 index 0000000000..a4b65c4d62 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/NameTableRenderer.svelte @@ -0,0 +1,38 @@ + + +
+ {#if value} +
+ x[0]) + .join("")} + /> +
+ {value} + {:else} +
-
+ {/if} +
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/OnboardingTypeModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/OnboardingTypeModal.svelte new file mode 100644 index 0000000000..7ec6d338d5 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/OnboardingTypeModal.svelte @@ -0,0 +1,108 @@ + + + chooseCreationType(selectedOnboardingType)} + disabled={!selectedOnboardingType} +> + +
{ + selectedOnboardingType = emailOnboardingKey + }} + > +
+ +
+ Send email invites +
+
+
+ {#if selectedOnboardingType == emailOnboardingKey} +
+ +
+ {/if} +
+
+ +
{ + selectedOnboardingType = basicOnboaridngKey + }} + > +
+ +
+ Generate passwords for each user +
+
+
+ {#if selectedOnboardingType == basicOnboaridngKey} +
+ +
+ {/if} +
+
+
+
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/PasswordCopyRenderer.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/PasswordCopyRenderer.svelte new file mode 100644 index 0000000000..00e0c6eeab --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/PasswordCopyRenderer.svelte @@ -0,0 +1,15 @@ + + +
+ {value} +
+ +
+
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/PasswordModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/PasswordModal.svelte new file mode 100644 index 0000000000..01dac8c222 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/PasswordModal.svelte @@ -0,0 +1,90 @@ + + + + All your new users can be accessed through the autogenerated passwords. + Make not of these passwords or download the csv + +
+
+ + +
+ Passwords CSV +
+
+
+ +
+ + + diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/RoleTableRenderer.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/RoleTableRenderer.svelte new file mode 100644 index 0000000000..4f481d374c --- /dev/null +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/RoleTableRenderer.svelte @@ -0,0 +1,16 @@ + + +
+ {value} +
+ + diff --git a/packages/builder/src/pages/builder/portal/manage/users/index.svelte b/packages/builder/src/pages/builder/portal/manage/users/index.svelte index 5a5f6c987a..d18881d1bb 100644 --- a/packages/builder/src/pages/builder/portal/manage/users/index.svelte +++ b/packages/builder/src/pages/builder/portal/manage/users/index.svelte @@ -1,52 +1,225 @@ + +
+ + {#if appGroups.length || appUsers.length} +
+ Access +
+ + Assign users to your app and define their access here + +
+
+ {#if hasGroupsLicense && appGroups.length} + + {#each appGroups as group} + + updateGroupRole(e.detail, group)} + autoWidth + quiet + value={group.roles[ + Object.keys(group.roles).find(x => x === fixedAppId) + ]} + /> + removeGroup(group)} + hoverable + size="S" + name="Close" + /> + + {/each} + + {/if} + {#if appUsers.length} + + {#each appUsers as user} + + updateUserRole(e.detail, user)} + autoWidth + quiet + value={user.roles[ + Object.keys(user.roles).find(x => x === fixedAppId) + ]} + /> + removeUser(user)} + hoverable + size="S" + name="Close" + /> + + {/each} + + + {/if} + {:else} +
+ + No users assigned +
+ Assign users to your app and set their access here +
+
+ +
+
+
+ {/if} +
+
+ + + + + + diff --git a/packages/builder/src/pages/builder/portal/overview/_components/AssignmentModal.svelte b/packages/builder/src/pages/builder/portal/overview/_components/AssignmentModal.svelte new file mode 100644 index 0000000000..d67697e9b1 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/overview/_components/AssignmentModal.svelte @@ -0,0 +1,105 @@ + + + addData(appData)} + showCloseIcon={false} +> + + {#each appData as input, index} + group.name} + getPrimaryOptionValue={group => group.name} + getPrimaryOptionIcon={group => group.icon} + getPrimaryOptionColour={group => group.colour} + getSecondaryOptionLabel={role => role.name} + getSecondaryOptionValue={role => role._id} + getSecondaryOptionColour={role => RoleUtils.getRoleColour(role._id)} + /> + {/each} + +
+ Add email +
+
diff --git a/packages/builder/src/pages/builder/portal/overview/_components/OverviewTab.svelte b/packages/builder/src/pages/builder/portal/overview/_components/OverviewTab.svelte index a1b9530c30..19402c213e 100644 --- a/packages/builder/src/pages/builder/portal/overview/_components/OverviewTab.svelte +++ b/packages/builder/src/pages/builder/portal/overview/_components/OverviewTab.svelte @@ -1,16 +1,17 @@
@@ -132,6 +141,38 @@ {/if}
+ { + navigateTab("Access") + }} + dataCy={"access"} + > +
+ {#if $users?.data?.length} + +
+ {#each $users?.data as user} + + {/each} +
+ +
+ {userCount} + {userCount > 1 ? `users have` : `user has`} access to this app +
+
+ {:else} + + No users +
+ No users have been assigned to this app +
+
+ {/if} +
+
{#if false}
@@ -186,6 +227,14 @@ grid-template-columns: repeat(auto-fill, minmax(30%, 1fr)); } + .users-tab { + display: flex; + gap: var(--spacing-m); + } + + .users-text { + color: var(--spectrum-global-color-gray-600); + } .overview-tab .bottom, .automation-metrics { display: grid; diff --git a/packages/builder/src/stores/portal/apps.js b/packages/builder/src/stores/portal/apps.js index b8fb8c5670..6323046eef 100644 --- a/packages/builder/src/stores/portal/apps.js +++ b/packages/builder/src/stores/portal/apps.js @@ -7,6 +7,17 @@ const extractAppId = id => { return split.length ? split[split.length - 1] : null } +const getProdAppID = appId => { + if (!appId || !appId.startsWith("app_dev")) { + return appId + } + // split to take off the app_dev element, then join it together incase any other app_ exist + const split = appId.split("app_dev") + split.shift() + const rest = split.join("app_dev") + return `${"app"}${rest}` +} + export function createAppStore() { const store = writable([]) @@ -78,6 +89,8 @@ export function createAppStore() { subscribe: store.subscribe, load, update, + extractAppId, + getProdAppID, } } diff --git a/packages/builder/src/stores/portal/groups.js b/packages/builder/src/stores/portal/groups.js new file mode 100644 index 0000000000..ca814ac057 --- /dev/null +++ b/packages/builder/src/stores/portal/groups.js @@ -0,0 +1,54 @@ +import { writable, get } from "svelte/store" +import { API } from "api" +import { auth } from "stores/portal" +import { Constants } from "@budibase/frontend-core" + +export function createGroupsStore() { + const store = writable([]) + + const actions = { + init: async () => { + // only init if these is a groups license, just to be sure but the feature will be blocked + // on the backend anyway + if ( + get(auth).user.license.features.includes(Constants.Features.USER_GROUPS) + ) { + const users = await API.getGroups() + store.set(users) + } + }, + + save: async group => { + const response = await API.saveGroup(group) + group._id = response._id + group._rev = response._rev + store.update(state => { + const currentIdx = state.findIndex(gr => gr._id === response._id) + if (currentIdx >= 0) { + state.splice(currentIdx, 1, group) + } else { + state.push(group) + } + return state + }) + }, + + delete: async group => { + await API.deleteGroup({ + id: group._id, + rev: group._rev, + }) + store.update(state => { + state = state.filter(state => state._id !== group._id) + return state + }) + }, + } + + return { + subscribe: store.subscribe, + actions, + } +} + +export const groups = createGroupsStore() diff --git a/packages/builder/src/stores/portal/index.js b/packages/builder/src/stores/portal/index.js index 8810ce6b74..b56ee94b00 100644 --- a/packages/builder/src/stores/portal/index.js +++ b/packages/builder/src/stores/portal/index.js @@ -7,3 +7,4 @@ export { auth } from "./auth" export { oidc } from "./oidc" export { templates } from "./templates" export { licensing } from "./licensing" +export { groups } from "./groups" diff --git a/packages/builder/src/stores/portal/users.js b/packages/builder/src/stores/portal/users.js index 12bce413b9..490d1bc9f6 100644 --- a/packages/builder/src/stores/portal/users.js +++ b/packages/builder/src/stores/portal/users.js @@ -22,15 +22,17 @@ export function createUsersStore() { return null } } + const fetch = async () => { + return await API.getUsers() + } - async function invite({ email, builder, admin }) { - return API.inviteUser({ - email, + async function invite({ emails, builder, admin }) { + return API.inviteUsers({ + emails, builder, admin, }) } - async function acceptInvite(inviteCode, password) { return API.acceptInvite({ inviteCode, @@ -38,28 +40,35 @@ export function createUsersStore() { }) } - async function create({ - email, - password, - admin, - builder, - forceResetPassword, - }) { - const body = { - email, - password, - roles: {}, - } - if (forceResetPassword) { - body.forceResetPassword = forceResetPassword - } - if (builder) { - body.builder = { global: true } - } - if (admin) { - body.admin = { global: true } - } - await API.saveUser(body) + async function create(data) { + let mappedUsers = data.users.map(user => { + const body = { + email: user.email, + password: user.password, + roles: {}, + } + if (user.forceResetPassword) { + body.forceResetPassword = user.forceResetPassword + } + + switch (user.role) { + case "appUser": + body.builder = { global: false } + body.admin = { global: false } + break + case "developer": + body.builder = { global: true } + break + case "admin": + body.admin = { global: true } + body.builder = { global: true } + break + } + + return body + }) + await API.createUsers({ users: mappedUsers, groups: data.groups }) + // re-search from first page await search() } @@ -69,18 +78,33 @@ export function createUsersStore() { update(users => users.filter(user => user._id !== id)) } - async function save(data) { - await API.saveUser(data) + async function getUserCountByApp({ appId }) { + return await API.getUserCountByApp({ appId }) } + async function bulkDelete(userIds) { + await API.deleteUsers(userIds) + } + + async function save(user) { + return await API.saveUser(user) + } + + const getUserRole = ({ admin, builder }) => + admin?.global ? "admin" : builder?.global ? "developer" : "appUser" + return { subscribe, search, get, + getUserRole, + fetch, invite, acceptInvite, create, save, + bulkDelete, + getUserCountByApp, delete: del, } } diff --git a/packages/builder/yarn.lock b/packages/builder/yarn.lock index 32f8767c03..88547fd4a6 100644 --- a/packages/builder/yarn.lock +++ b/packages/builder/yarn.lock @@ -5733,9 +5733,9 @@ svelte-portal@0.1.0: integrity sha512-kef+ksXVKun224mRxat+DdO4C+cGHla+fEcZfnBAvoZocwiaceOfhf5azHYOPXSSB1igWVFTEOF3CDENPnuWxg== svelte@^3.48.0: - version "3.48.0" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.48.0.tgz#f98c866d45e155bad8e1e88f15f9c03cd28753d3" - integrity sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ== + version "3.49.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" + integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== symbol-tree@^3.2.4: version "3.2.4" diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore index 988d7b9a6b..efef4f97c8 100644 --- a/packages/cli/.gitignore +++ b/packages/cli/.gitignore @@ -4,3 +4,4 @@ nginx.conf build/ docker-error.log envoy.yaml +*.tar.gz diff --git a/packages/cli/package.json b/packages/cli/package.json index a9212b06cc..8cde5fe568 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { @@ -9,28 +9,43 @@ "author": "Budibase", "license": "GPL-3.0", "scripts": { - "build": "pkg . --out-path build" + "prebuild": "rm -rf prebuilds 2> /dev/null && cp -r node_modules/leveldown/prebuilds prebuilds", + "build": "yarn prebuild && renamer --find .node --replace .fake 'prebuilds/**' && pkg . --out-path build && yarn postbuild", + "postbuild": "rm -rf prebuilds 2> /dev/null" }, "pkg": { "targets": [ - "node14-linux", - "node14-win", - "node14-macos" + "node16-linux", + "node16-win", + "node16-macos" + ], + "assets": [ + "node_modules/@budibase/backend-core/dist/**/*", + "prebuilds/**/*" ], "outputPath": "build" }, "dependencies": { - "axios": "^0.21.1", - "chalk": "^4.1.0", - "commander": "^7.1.0", - "docker-compose": "^0.23.6", - "inquirer": "^8.0.0", - "lookpath": "^1.1.0", - "pkg": "^5.3.0", + "@budibase/backend-core": "1.1.32-alpha.6", + "axios": "0.21.2", + "chalk": "4.1.0", + "cli-progress": "3.11.2", + "commander": "7.1.0", + "docker-compose": "0.23.6", + "dotenv": "16.0.1", + "inquirer": "8.0.0", + "lookpath": "1.1.0", + "node-fetch": "2", + "pkg": "5.7.0", "posthog-node": "1.0.7", - "randomstring": "^1.1.5" + "pouchdb": "7.3.0", + "pouchdb-replication-stream": "1.2.9", + "randomstring": "1.1.5", + "tar": "6.1.11" }, "devDependencies": { - "eslint": "^7.20.0" + "copyfiles": "^2.4.1", + "eslint": "^7.20.0", + "renamer": "^4.0.0" } } diff --git a/packages/cli/src/backups/index.js b/packages/cli/src/backups/index.js new file mode 100644 index 0000000000..697dafac6f --- /dev/null +++ b/packages/cli/src/backups/index.js @@ -0,0 +1,121 @@ +const Command = require("../structures/Command") +const { CommandWords } = require("../constants") +const fs = require("fs") +const { join } = require("path") +const { getAllDbs } = require("../core/db") +const tar = require("tar") +const { progressBar } = require("../utils") +const { + TEMP_DIR, + COUCH_DIR, + MINIO_DIR, + getConfig, + replication, + getPouches, +} = require("./utils") +const { exportObjects, importObjects } = require("./objectStore") + +async function exportBackup(opts) { + const envFile = opts.env || undefined + let filename = opts["export"] || opts + if (typeof filename !== "string") { + filename = `backup-${new Date().toISOString()}.tar.gz` + } + const config = await getConfig(envFile) + const dbList = await getAllDbs(config["COUCH_DB_URL"]) + const { Remote, Local } = getPouches(config) + if (fs.existsSync(TEMP_DIR)) { + fs.rmSync(TEMP_DIR, { recursive: true }) + } + const couchDir = join(TEMP_DIR, COUCH_DIR) + fs.mkdirSync(TEMP_DIR) + fs.mkdirSync(couchDir) + console.log("CouchDB Export") + const bar = progressBar(dbList.length) + let count = 0 + for (let db of dbList) { + bar.update(++count) + const remote = new Remote(db) + const local = new Local(join(TEMP_DIR, COUCH_DIR, db)) + await replication(remote, local) + } + bar.stop() + console.log("S3 Export") + await exportObjects() + tar.create( + { + sync: true, + gzip: true, + file: filename, + cwd: join(TEMP_DIR), + }, + [COUCH_DIR, MINIO_DIR] + ) + fs.rmSync(TEMP_DIR, { recursive: true }) + console.log(`Generated export file - ${filename}`) +} + +async function importBackup(opts) { + const envFile = opts.env || undefined + const filename = opts["import"] || opts + const config = await getConfig(envFile) + if (!filename || !fs.existsSync(filename)) { + console.error("Cannot import without specifying a valid file to import") + process.exit(-1) + } + if (fs.existsSync(TEMP_DIR)) { + fs.rmSync(TEMP_DIR, { recursive: true }) + } + fs.mkdirSync(TEMP_DIR) + tar.extract({ + sync: true, + cwd: join(TEMP_DIR), + file: filename, + }) + const { Remote, Local } = getPouches(config) + const dbList = fs.readdirSync(join(TEMP_DIR, COUCH_DIR)) + console.log("CouchDB Import") + const bar = progressBar(dbList.length) + let count = 0 + for (let db of dbList) { + bar.update(++count) + const remote = new Remote(db) + const local = new Local(join(TEMP_DIR, COUCH_DIR, db)) + await replication(local, remote) + } + bar.stop() + console.log("MinIO Import") + await importObjects() + console.log("Import complete") + fs.rmSync(TEMP_DIR, { recursive: true }) +} + +async function pickOne(opts) { + if (opts["import"]) { + return importBackup(opts) + } else if (opts["export"]) { + return exportBackup(opts) + } +} + +const command = new Command(`${CommandWords.BACKUPS}`) + .addHelp( + "Allows building backups of Budibase, as well as importing a backup to a new instance." + ) + .addSubOption( + "--export [filename]", + "Export a backup from an existing Budibase installation.", + exportBackup + ) + .addSubOption( + "--import [filename]", + "Import a backup to a new Budibase installation.", + importBackup + ) + .addSubOption( + "--env [envFile]", + "Provide an environment variable file to configure the CLI.", + pickOne + ) + +exports.command = command diff --git a/packages/cli/src/backups/objectStore.js b/packages/cli/src/backups/objectStore.js new file mode 100644 index 0000000000..b0bf99891d --- /dev/null +++ b/packages/cli/src/backups/objectStore.js @@ -0,0 +1,63 @@ +const { + ObjectStoreBuckets, + ObjectStore, + retrieve, + uploadDirectory, + makeSureBucketExists, +} = require("@budibase/backend-core/objectStore") +const fs = require("fs") +const { join } = require("path") +const { TEMP_DIR, MINIO_DIR } = require("./utils") +const { progressBar } = require("../utils") + +const bucketList = Object.values(ObjectStoreBuckets) + +exports.exportObjects = async () => { + const path = join(TEMP_DIR, MINIO_DIR) + fs.mkdirSync(path) + let fullList = [] + for (let bucket of bucketList) { + const client = ObjectStore(bucket) + try { + await client.headBucket().promise() + } catch (err) { + continue + } + const list = await client.listObjectsV2().promise() + fullList = fullList.concat(list.Contents.map(el => ({ ...el, bucket }))) + } + const bar = progressBar(fullList.length) + let count = 0 + for (let object of fullList) { + const filename = object.Key + const data = await retrieve(object.bucket, filename) + const possiblePath = filename.split("/") + if (possiblePath.length > 1) { + const dirs = possiblePath.slice(0, possiblePath.length - 1) + fs.mkdirSync(join(path, object.bucket, ...dirs), { recursive: true }) + } + fs.writeFileSync(join(path, object.bucket, ...possiblePath), data) + bar.update(++count) + } + bar.stop() +} + +exports.importObjects = async () => { + const path = join(TEMP_DIR, MINIO_DIR) + const buckets = fs.readdirSync(path) + let total = 0 + buckets.forEach(bucket => { + const files = fs.readdirSync(join(path, bucket)) + total += files.length + }) + const bar = progressBar(total) + let count = 0 + for (let bucket of buckets) { + const client = ObjectStore(bucket) + await makeSureBucketExists(client, bucket) + const files = await uploadDirectory(bucket, join(path, bucket), "/") + count += files.length + bar.update(count) + } + bar.stop() +} diff --git a/packages/cli/src/backups/utils.js b/packages/cli/src/backups/utils.js new file mode 100644 index 0000000000..5d941aa17c --- /dev/null +++ b/packages/cli/src/backups/utils.js @@ -0,0 +1,88 @@ +const dotenv = require("dotenv") +const fs = require("fs") +const { string } = require("../questions") +const { getPouch } = require("../core/db") + +exports.DEFAULT_COUCH = "http://budibase:budibase@localhost:10000/db/" +exports.DEFAULT_MINIO = "http://localhost:10000/" +exports.TEMP_DIR = ".temp" +exports.COUCH_DIR = "couchdb" +exports.MINIO_DIR = "minio" + +const REQUIRED = [ + { value: "MAIN_PORT", default: "10000" }, + { value: "COUCH_DB_URL", default: exports.DEFAULT_COUCH }, + { value: "MINIO_URL", default: exports.DEFAULT_MINIO }, + { value: "MINIO_ACCESS_KEY" }, + { value: "MINIO_SECRET_KEY" }, +] + +exports.checkURLs = config => { + const mainPort = config["MAIN_PORT"], + username = config["COUCH_DB_USER"], + password = config["COUCH_DB_PASSWORD"] + if (!config["COUCH_DB_URL"] && mainPort && username && password) { + config[ + "COUCH_DB_URL" + ] = `http://${username}:${password}@localhost:${mainPort}/db/` + } + if (!config["MINIO_URL"]) { + config["MINIO_URL"] = exports.DEFAULT_MINIO + } + return config +} + +exports.askQuestions = async () => { + console.log( + "*** NOTE: use a .env file to load these parameters repeatedly ***" + ) + let config = {} + for (let property of REQUIRED) { + config[property.value] = await string(property.value, property.default) + } + return config +} + +exports.loadEnvironment = path => { + if (!fs.existsSync(path)) { + throw "Unable to file specified .env file" + } + const env = fs.readFileSync(path, "utf8") + const config = exports.checkURLs(dotenv.parse(env)) + for (let required of REQUIRED) { + if (!config[required.value]) { + throw `Cannot find "${required.value}" property in .env file` + } + } + return config +} + +// true is the default value passed by commander +exports.getConfig = async (envFile = true) => { + let config + if (envFile !== true) { + config = exports.loadEnvironment(envFile) + } else { + config = await exports.askQuestions() + } + return config +} + +exports.replication = (from, to) => { + return new Promise((resolve, reject) => { + from.replicate + .to(to) + .on("complete", () => { + resolve() + }) + .on("error", err => { + reject(err) + }) + }) +} + +exports.getPouches = config => { + const Remote = getPouch(config["COUCH_DB_URL"]) + const Local = getPouch() + return { Remote, Local } +} diff --git a/packages/cli/src/constants.js b/packages/cli/src/constants.js index 21eaf09d9c..5d66c3a39d 100644 --- a/packages/cli/src/constants.js +++ b/packages/cli/src/constants.js @@ -1,4 +1,5 @@ exports.CommandWords = { + BACKUPS: "backups", HOSTING: "hosting", ANALYTICS: "analytics", HELP: "help", diff --git a/packages/cli/src/core/db.js b/packages/cli/src/core/db.js new file mode 100644 index 0000000000..38f383d99e --- /dev/null +++ b/packages/cli/src/core/db.js @@ -0,0 +1,38 @@ +const PouchDB = require("pouchdb") +const { checkSlashesInUrl } = require("../utils") +const fetch = require("node-fetch") + +/** + * Fully qualified URL including username and password, or nothing for local + */ +exports.getPouch = (url = undefined) => { + let POUCH_DB_DEFAULTS = {} + if (!url) { + POUCH_DB_DEFAULTS = { + prefix: undefined, + adapter: "leveldb", + } + } else { + POUCH_DB_DEFAULTS = { + prefix: url, + } + } + const replicationStream = require("pouchdb-replication-stream") + PouchDB.plugin(replicationStream.plugin) + PouchDB.adapter("writableStream", replicationStream.adapters.writableStream) + return PouchDB.defaults(POUCH_DB_DEFAULTS) +} + +exports.getAllDbs = async url => { + const response = await fetch( + checkSlashesInUrl(encodeURI(`${url}/_all_dbs`)), + { + method: "GET", + } + ) + if (response.status === 200) { + return await response.json() + } else { + throw "Cannot connect to CouchDB instance" + } +} diff --git a/packages/cli/src/index.js b/packages/cli/src/index.js index 6693446b39..0a3ced4200 100644 --- a/packages/cli/src/index.js +++ b/packages/cli/src/index.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +require("./prebuilds") const { getCommands } = require("./options") const { Command } = require("commander") const { getHelpDescription } = require("./utils") diff --git a/packages/cli/src/options.js b/packages/cli/src/options.js index 1cafbf9269..1ac66df9fb 100644 --- a/packages/cli/src/options.js +++ b/packages/cli/src/options.js @@ -1,6 +1,7 @@ const analytics = require("./analytics") const hosting = require("./hosting") +const backups = require("./backups") exports.getCommands = () => { - return [hosting.command, analytics.command] + return [hosting.command, analytics.command, backups.command] } diff --git a/packages/cli/src/prebuilds.js b/packages/cli/src/prebuilds.js new file mode 100644 index 0000000000..ecc59f964a --- /dev/null +++ b/packages/cli/src/prebuilds.js @@ -0,0 +1,34 @@ +const os = require("os") +const { join } = require("path") +const fs = require("fs") +const PREBUILDS = "prebuilds" +const ARCH = `${os.platform()}-${os.arch()}` +const PREBUILD_DIR = join(process.execPath, "..", PREBUILDS, ARCH) + +checkForBinaries() + +function checkForBinaries() { + const readDir = join(__filename, "..", "..", PREBUILDS, ARCH) + if (fs.existsSync(PREBUILD_DIR) || !fs.existsSync(readDir)) { + return + } + const natives = fs.readdirSync(readDir) + if (fs.existsSync(readDir)) { + fs.mkdirSync(PREBUILD_DIR, { recursive: true }) + for (let native of natives) { + const filename = `${native.split(".fake")[0]}.node` + fs.cpSync(join(readDir, native), join(PREBUILD_DIR, filename)) + } + } +} + +function cleanup() { + if (fs.existsSync(PREBUILD_DIR)) { + fs.rmSync(PREBUILD_DIR, { recursive: true }) + } +} + +const events = ["exit", "SIGINT", "SIGUSR1", "SIGUSR2", "uncaughtException"] +events.forEach(event => { + process.on(event, cleanup) +}) diff --git a/packages/cli/src/structures/Command.js b/packages/cli/src/structures/Command.js index a8d24566be..dfce96504d 100644 --- a/packages/cli/src/structures/Command.js +++ b/packages/cli/src/structures/Command.js @@ -39,8 +39,10 @@ class Command { let executed = false for (let opt of thisCmd.opts) { const lookup = opt.command.split(" ")[0].replace("--", "") - if (options[lookup]) { - await opt.func(options[lookup]) + if (!executed && options[lookup]) { + const input = + Object.keys(options).length > 1 ? options : options[lookup] + await opt.func(input) executed = true } } diff --git a/packages/cli/src/utils.js b/packages/cli/src/utils.js index f61636389d..818153ef02 100644 --- a/packages/cli/src/utils.js +++ b/packages/cli/src/utils.js @@ -2,6 +2,7 @@ const chalk = require("chalk") const fs = require("fs") const axios = require("axios") const path = require("path") +const progress = require("cli-progress") exports.downloadFile = async (url, filePath) => { filePath = path.resolve(filePath) @@ -56,3 +57,13 @@ exports.parseEnv = env => { } return result } + +exports.progressBar = total => { + const bar = new progress.SingleBar({}, progress.Presets.shades_classic) + bar.start(total, 0) + return bar +} + +exports.checkSlashesInUrl = url => { + return url.replace(/(https?:\/\/)|(\/)+/g, "$1$2") +} diff --git a/packages/cli/yarn.lock b/packages/cli/yarn.lock index 39fc4ed990..19e76101ad 100644 --- a/packages/cli/yarn.lock +++ b/packages/cli/yarn.lock @@ -4,49 +4,91 @@ "@babel/code-frame@7.12.11": version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== dependencies: "@babel/highlight" "^7.10.4" -"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.15.7": +"@babel/helper-validator-identifier@^7.15.7": version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== +"@babel/helper-validator-identifier@^7.16.7": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + "@babel/highlight@^7.10.4": version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz" integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== dependencies: "@babel/helper-validator-identifier" "^7.15.7" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@7.13.13": - version "7.13.13" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df" - integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw== +"@babel/parser@7.17.10": + version "7.17.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.10.tgz#873b16db82a8909e0fbd7f115772f4b739f6ce78" + integrity sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ== "@babel/runtime@^7.15.4": version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz" integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== dependencies: regenerator-runtime "^0.13.4" -"@babel/types@7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.12.tgz#edbf99208ef48852acdff1c8a681a1e4ade580cd" - integrity sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA== +"@babel/types@7.17.10": + version "7.17.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.10.tgz#d35d7b4467e439fcf06d195f8100e0fea7fc82c4" + integrity sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" + "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@budibase/backend-core@1.1.32-alpha.6": + version "1.1.32-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.1.32-alpha.6.tgz#e9dc1a1989a2a6952f5ce002fcdfef66625f3de8" + integrity sha512-8oT6veeSmymuJfnu1jAkDAWD4fLj5W0KxNq6GlC+eMWWDZloDF4fMWDpuYTFBeinq1z1GeSFXc9Ak6u+1Z7LtQ== + dependencies: + "@budibase/types" "1.1.32-alpha.6" + "@techpass/passport-openidconnect" "0.3.2" + aws-sdk "2.1030.0" + bcrypt "5.0.1" + dotenv "16.0.1" + emitter-listener "1.1.2" + ioredis "4.28.0" + jsonwebtoken "8.5.1" + koa-passport "4.1.4" + lodash "4.17.21" + lodash.isarguments "3.1.0" + node-fetch "2.6.7" + passport-google-auth "1.0.2" + passport-google-oauth "2.0.0" + passport-jwt "4.0.0" + passport-local "1.0.0" + passport-oauth2-refresh "^2.1.0" + posthog-node "1.3.0" + pouchdb "7.3.0" + pouchdb-find "7.2.2" + pouchdb-replication-stream "1.2.9" + redlock "4.2.0" + sanitize-s3-objectkey "0.0.1" + semver "7.3.7" + tar-fs "2.1.1" + uuid "8.3.2" + zlib "1.0.5" + +"@budibase/types@1.1.32-alpha.6": + version "1.1.32-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.1.32-alpha.6.tgz#95d8d73c7ed6ebc22ff26a44365127a478e19409" + integrity sha512-AKKxrzVqGtcSzZZ2fP6i2Vgv6ICN9NEEE1dmzRk9AImZS+XKQ9VgVpdE+4gHgFK7L0gBYAsiaoEpCbbrI/+NoQ== + "@eslint/eslintrc@^0.4.3": version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz" integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== dependencies: ajv "^6.12.4" @@ -61,7 +103,7 @@ "@humanwhocodes/config-array@^0.5.0": version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz" integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== dependencies: "@humanwhocodes/object-schema" "^1.2.0" @@ -70,12 +112,27 @@ "@humanwhocodes/object-schema@^1.2.0": version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" + integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" @@ -83,35 +140,80 @@ "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3": version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@techpass/passport-openidconnect@0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.2.tgz#f8fd5d97256286665dbf26dac92431f977ab1e63" + integrity sha512-fnCtEiexXSHA029B//hJcCJlLJrT3lhpNCyA0rnz58Qttz0BLGCVv6yMT8HmOnGThH6vcDOVwdgKM3kbCQtEhw== + dependencies: + base64url "^3.0.1" + oauth "^0.9.15" + passport-strategy "^1.0.0" + request "^2.88.0" + webfinger "^0.4.2" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abort-controller@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +abstract-leveldown@^6.2.1: + version "6.3.0" + resolved "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz" + integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: + version "6.2.3" + resolved "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz" + integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + acorn-jsx@^5.3.1: version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn@^7.4.0: version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== agent-base@6: version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -123,7 +225,7 @@ ajv@^6.10.0, ajv@^6.12.4: ajv@^8.0.1: version "8.8.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.1.tgz#e73dd88eeb4b10bbcd82bee136e6fbe801664d18" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.8.1.tgz" integrity sha512-6CiMNDrzv0ZR916u2T+iRunnD60uWmNn8SkdB44/6stVORUg0aAkWO7PkOhpCmjmW8f2I/G/xnowD66fxGyQJg== dependencies: fast-deep-equal "^3.1.1" @@ -133,48 +235,61 @@ ajv@^8.0.1: ansi-colors@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-escapes@^4.2.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" aproba@^1.0.3: version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + are-we-there-yet@~1.1.2: version "1.1.7" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz" integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== dependencies: delegates "^1.0.0" @@ -182,68 +297,176 @@ are-we-there-yet@~1.1.2: argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" +argsarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz" + integrity sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg== + +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + +array-back@^6.2.0, array-back@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-6.2.2.tgz#f567d99e9af88a6d3d2f9dfcc21db6f9ba9fd157" + integrity sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw== + array-union@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== array-uniq@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d" + resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz" integrity sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0= +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + astral-regex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" + integrity sha512-+g/Ncjbx0JSq2Mk03WQkyKvNh5q9Qvyo/RIqIqnmC5feJY70PNl2ESwZU2BhAB+AZPkHNzzyC2Dq2AS5VnTKhQ== + dependencies: + lodash "^4.14.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + at-least-node@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== +aws-sdk@2.1030.0: + version "2.1030.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1030.0.tgz#24a856af3d2b8b37c14a8f59974993661c66fd82" + integrity sha512-to0STOb8DsSGuSsUb/WCbg/UFnMGfIYavnJH5ZlRCHzvCFjTyR+vfE8ku+qIZvfFM4+5MNTQC/Oxfun2X/TuyA== + dependencies: + buffer "4.9.2" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + axios-retry@^3.1.9: version "3.2.4" - resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.2.4.tgz#f447a53c3456f5bfeca18f20c3a3272207d082ae" + resolved "https://registry.npmjs.org/axios-retry/-/axios-retry-3.2.4.tgz" integrity sha512-Co3UXiv4npi6lM963mfnuH90/YFLKWWDmoBYfxkHT5xtkSSWNqK9zdG3fw5/CP/dsoKB5aMMJCsgab+tp1OxLQ== dependencies: "@babel/runtime" "^7.15.4" is-retry-allowed "^2.2.0" +axios@0.21.2: + version "0.21.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.2.tgz#21297d5084b2aeeb422f5d38e7be4fbb82239017" + integrity sha512-87otirqUw3e8CzHTMO+/9kh/FSgXt/eVDvipijwDtEuwbkySWZ9SBm6VEubmJ/kLKEoLQV/POhxXFb66bfekfg== + dependencies: + follow-redirects "^1.14.0" + +axios@0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== + dependencies: + follow-redirects "^1.14.4" + axios@^0.21.1: version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: follow-redirects "^1.14.0" balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.3.1: +base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -bl@^4.0.3, bl@^4.1.0: +base64url@3.x.x, base64url@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +bcrypt@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71" + integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + node-addon-api "^3.1.0" + +bl@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: buffer "^5.5.0" inherits "^2.0.4" readable-stream "^3.4.0" +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -251,14 +474,38 @@ brace-expansion@^1.1.7: braces@^3.0.1: version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -buffer@^5.5.0: +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer-from@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-from@1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" @@ -266,21 +513,34 @@ buffer@^5.5.0: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -chalk@^2.0.0: +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +chalk@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -288,107 +548,169 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: chardet@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== charenc@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= chownr@^1.1.1: version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + cli-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== dependencies: restore-cursor "^3.1.0" -cli-spinners@^2.5.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== +cli-progress@3.11.2: + version "3.11.2" + resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.11.2.tgz#f8c89bd157e74f3f2c43bcfb3505670b4d48fc77" + integrity sha512-lCPoS6ncgX4+rJu5bS3F/iCz17kZ9MPZ6dpuTtI0KXKABkhyXIdYB3Inby1OpaGti3YlI3EeEkM9AuWpelJrVA== + dependencies: + string-width "^4.2.3" cli-width@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== cliui@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" wrap-ansi "^7.0.0" -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= +clone-buffer@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz" + integrity sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g== + +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -commander@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +command-line-args@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.1.1: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + +commander@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff" + integrity sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg== component-type@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" + resolved "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz" integrity sha1-ikeQFwAjjk/DIml3EjAibyS0Fak= concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -console-control-strings@^1.0.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +copyfiles@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" + integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== + dependencies: + glob "^7.0.5" + minimatch "^3.0.3" + mkdirp "^1.0.4" + noms "0.0.0" + through2 "^2.0.1" + untildify "^4.0.0" + yargs "^16.1.0" + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== core-util-is@~1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== cross-spawn@^7.0.2: version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -397,108 +719,197 @@ cross-spawn@^7.0.2: crypt@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + resolved "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= +current-module-paths@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/current-module-paths/-/current-module-paths-1.1.0.tgz#5d5bf214281d80aea264e642f028e672098238f6" + integrity sha512-HGhLUszcgprjKmzvQoCQda8iEWsQn3sWVzPdttyJVR5cjfVDYcoyozQA5D1YXgab9v84SPMpSuD+YrPX6i1IMQ== + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + debug@4, debug@^4.0.1, debug@^4.1.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== dependencies: ms "2.1.2" +debug@^4.3.1: + 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" + decompress-response@^4.2.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz" integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== dependencies: mimic-response "^2.0.0" -deep-extend@^0.6.0: +deep-extend@^0.6.0, deep-extend@~0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= +deferred-leveldown@~5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz" + integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== dependencies: - clone "^1.0.2" + abstract-leveldown "~6.2.1" + inherits "^2.0.3" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + detect-libc@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-libc@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" + integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== + dir-glob@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" -docker-compose@^0.23.6: - version "0.23.13" - resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.23.13.tgz#77d37bd05b6a966345f631e6d05e961c79514f06" - integrity sha512-/9fYC4g3AO+qsqxIZhmbVnFvJJPcYEV2yJbAPPXH+6AytU3urIY8lUAXOlvY8sl4u25pdKu1JrOfAmWC7lJDJg== - dependencies: - yaml "^1.10.2" +docker-compose@0.23.6: + version "0.23.6" + resolved "https://registry.yarnpkg.com/docker-compose/-/docker-compose-0.23.6.tgz#bd21e17d599f17fcf7a4b5d607cff0358a9c378b" + integrity sha512-y3Q8MkwG862rNqkvEQG59/7Fi2/fzs3NYDCvqUAAD+z0WGs2qcJ9hRcn34hWgWv9ouPkFqe3Vwca0h+4bIIRWw== doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" +dotenv@16.0.1: + version "16.0.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" + integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== + +double-ended-queue@2.1.0-0: + version "2.1.0-0" + resolved "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz" + integrity sha512-+BNfZ+deCo8hMNpDqDnvT+c0XpJ5cUa6mqYq89bho2Ifze4URTqRkcwR399hWoTrTkbZ/XJYDgP6rc7pRgffEQ== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +emitter-listener@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" + integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== + dependencies: + shimmer "^1.2.0" + emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +encoding-down@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz" + integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== + dependencies: + abstract-leveldown "^6.2.1" + inherits "^2.0.3" + level-codec "^9.0.0" + level-errors "^2.0.0" + end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" +end-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/end-stream/-/end-stream-0.1.0.tgz" + integrity sha512-Brl10T8kYnc75IepKizW6Y9liyW8ikz1B7n/xoHrJxoVSSjoqPn30sb7XVFfQERK4QfUMYRGs9dhWwtt2eu6uA== + dependencies: + write-stream "~0.4.3" + enquirer@^2.3.5: version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== dependencies: ansi-colors "^4.1.1" +errno@~0.1.1: + version "0.1.8" + resolved "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + escalade@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== escodegen@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz" integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== dependencies: esprima "^4.0.1" @@ -510,7 +921,7 @@ escodegen@^2.0.0: eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" @@ -518,24 +929,24 @@ eslint-scope@^5.1.1: eslint-utils@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== eslint-visitor-keys@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== eslint@^7.20.0: version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz" integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== dependencies: "@babel/code-frame" "7.12.11" @@ -581,7 +992,7 @@ eslint@^7.20.0: espree@^7.3.0, espree@^7.3.1: version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== dependencies: acorn "^7.4.0" @@ -590,61 +1001,91 @@ espree@^7.3.0, espree@^7.3.1: esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^4.1.1: version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +events@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== + expand-template@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + external-editor@^3.0.3: version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz" integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: chardet "^0.7.0" iconv-lite "^0.4.24" tmp "^0.0.33" +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.1.1: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== +fast-diff@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -654,45 +1095,74 @@ fast-glob@^3.1.1: fast-json-stable-stringify@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fastq@^1.6.0: version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" +fetch-cookie@0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.10.1.tgz#5ea88f3d36950543c87997c27ae2aeafb4b5c4d4" + integrity sha512-beB+VEd4cNeVG1PY+ee74+PkuCQnik78pgLi5Ah/7qdUfov8IctU0vLUbBT8/10Ma5GMBeI4wtxhGrEfKNYs2g== + dependencies: + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" + +fetch-cookie@0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== + dependencies: + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" + figures@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== dependencies: escape-string-regexp "^1.0.5" file-entry-cache@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" +file-set@^5.1.2: + version "5.1.3" + resolved "https://registry.yarnpkg.com/file-set/-/file-set-5.1.3.tgz#44dde6a8ae52d69813ee22beccd7cfe28bc655d2" + integrity sha512-mQ6dqz+z59on3B50IGF3ujNGbZmY1TAeLHpNfhLEeNM6Lky31w3RUlbCyqZWQs0DuZJQU4R2qDuVd9ojyzadcg== + dependencies: + array-back "^6.2.2" + glob "^7.2.0" + fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + flat-cache@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: flatted "^3.1.0" @@ -700,17 +1170,31 @@ flat-cache@^3.0.4: flatted@^3.1.0: version "3.2.4" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz" integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== -follow-redirects@^1.14.0: - version "1.14.8" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" - integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== +follow-redirects@^1.14.0, follow-redirects@^1.14.4: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" from2@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz" integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= dependencies: inherits "^2.0.1" @@ -718,12 +1202,12 @@ from2@^2.3.0: fs-constants@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-extra@^9.1.0: version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== dependencies: at-least-node "^1.0.0" @@ -731,24 +1215,46 @@ fs-extra@^9.1.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" 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" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gauge@~2.7.3: version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz" integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" @@ -762,24 +1268,43 @@ gauge@~2.7.3: get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + github-from-package@0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= glob-parent@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob@^7.0.5, glob@^7.2.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.1.3: version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" @@ -789,55 +1314,120 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +global-dirs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" + integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== + dependencies: + ini "2.0.0" + globals@^13.6.0, globals@^13.9.0: version "13.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + resolved "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz" integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== dependencies: type-fest "^0.20.2" -globby@^11.0.3: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" slash "^3.0.0" +google-auth-library@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" + integrity sha512-KM54Y9GhdAzfXUHmWEoYmaOykSLuMG7W4HvVLYqyogxOyE6px8oSS8W13ngqW0oDGZ915GFW3V6OM6+qcdvPOA== + dependencies: + gtoken "^1.2.1" + jws "^3.1.4" + lodash.noop "^3.0.1" + request "^2.74.0" + +google-p12-pem@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177" + integrity sha512-puhMlJ2+E/rgvxWaqgN/nC7x623OAE8MR9vBUqxF0inCE7HoVfCHvTeQ9+BR+rj9KM0fIg6XV6tmbt7XHHssoQ== + dependencies: + node-forge "^0.7.1" + +googleapis@^16.0.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576" + integrity sha512-5czmF7xkIlJKc1+/+5tltrI1skoR3HKtkDOld9rk+DOucTpZRjOhCoJzoSjxB3M8rP2tEb1VIr1TPyzR3V2PUQ== + dependencies: + async "~2.1.4" + google-auth-library "~0.10.0" + string-template "~1.0.0" + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +gtoken@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8" + integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w== + dependencies: + google-p12-pem "^0.1.0" + jws "^3.0.0" + mime "^1.4.1" + request "^2.72.0" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-unicode@^2.0.0: +has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== has@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-proxy-agent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz" integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== dependencies: agent-base "6" @@ -845,29 +1435,44 @@ https-proxy-agent@^5.0.0: iconv-lite@^0.4.24: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.13: +ieee754@1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +ieee754@^1.1.13, ieee754@^1.1.4: version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4: - version "5.1.9" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" - integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +immediate@3.3.0, immediate@^3.2.3: + version "3.3.0" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz" + integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" @@ -875,166 +1480,351 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + ini@~1.3.0: version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@^8.0.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" - integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== +inquirer@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.0.0.tgz#957a46db1abcf0fdd2ab82deb7470e90afc7d0ac" + integrity sha512-ON8pEJPPCdyjxj+cxsYRe6XfCJepTxANdNnTebsTuQgXpRyZRRT9t4dJwjRubgmvn20CLSEnozRUayXyM9VTXA== dependencies: ansi-escapes "^4.2.1" - chalk "^4.1.1" + chalk "^4.1.0" cli-cursor "^3.1.0" cli-width "^3.0.0" external-editor "^3.0.3" figures "^3.0.0" lodash "^4.17.21" mute-stream "0.0.8" - ora "^5.4.1" run-async "^2.4.0" - rxjs "^7.2.0" + rxjs "^6.6.6" string-width "^4.1.0" strip-ansi "^6.0.0" through "^2.3.6" into-stream@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-6.0.0.tgz#4bfc1244c0128224e18b8870e85b2de8e66c6702" + resolved "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz" integrity sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA== dependencies: from2 "^2.3.0" p-is-promise "^3.0.0" +ioredis@4.28.0: + version "4.28.0" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.0.tgz#5a2be3f37ff2075e2332f280eaeb02ab4d9ff0d3" + integrity sha512-I+zkeeWp3XFgPT2CtJKxvaF5FjGBGt4yGYljRjQecdQKteThuAsKqffeF1lgHVlYnuNeozRbPOCDNZ7tDWPeig== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + is-buffer@~1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-core-module@^2.2.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" - integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== +is-core-module@2.9.0, is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== dependencies: has "^1.0.3" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-glob@^4.0.0, is-glob@^4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-retry-allowed@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" + resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz" integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -isarray@~1.0.0: +is-typedarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + +jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + integrity sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w== + join-component@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5" + resolved "https://registry.npmjs.org/join-component/-/join-component-1.1.0.tgz" integrity sha1-uEF7dQZho5K+4sJTfGiyqdSXfNU= js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema-traverse@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + jsonfile@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== dependencies: universalify "^2.0.0" optionalDependencies: graceful-fs "^4.1.6" +jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +koa-passport@4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa" + integrity sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg== + dependencies: + passport "^0.4.0" + +level-codec@9.0.2, level-codec@^9.0.0: + version "9.0.2" + resolved "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz" + integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== + dependencies: + buffer "^5.6.0" + +level-concat-iterator@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz" + integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== + +level-errors@^2.0.0, level-errors@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz" + integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== + dependencies: + errno "~0.1.1" + +level-iterator-stream@~4.0.0: + version "4.0.2" + resolved "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz" + integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== + dependencies: + inherits "^2.0.4" + readable-stream "^3.4.0" + xtend "^4.0.2" + +level-js@^5.0.0: + version "5.0.2" + resolved "https://registry.npmjs.org/level-js/-/level-js-5.0.2.tgz" + integrity sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg== + dependencies: + abstract-leveldown "~6.2.3" + buffer "^5.5.0" + inherits "^2.0.3" + ltgt "^2.1.2" + +level-packager@^5.1.0: + version "5.1.1" + resolved "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz" + integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== + dependencies: + encoding-down "^6.3.0" + levelup "^4.3.2" + +level-supports@~1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz" + integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== + dependencies: + xtend "^4.0.2" + +level-write-stream@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/level-write-stream/-/level-write-stream-1.0.0.tgz" + integrity sha512-bBNKOEOMl8msO+uIM9YX/gUO6ckokZ/4pCwTm/lwvs46x6Xs8Zy0sn3Vh37eDqse4mhy4fOMIb/JsSM2nyQFtw== + dependencies: + end-stream "~0.1.0" + +level@6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/level/-/level-6.0.1.tgz" + integrity sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw== + dependencies: + level-js "^5.0.0" + level-packager "^5.1.0" + leveldown "^5.4.0" + +leveldown@5.6.0, leveldown@^5.4.0: + version "5.6.0" + resolved "https://registry.npmjs.org/leveldown/-/leveldown-5.6.0.tgz" + integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== + dependencies: + abstract-leveldown "~6.2.1" + napi-macros "~2.0.0" + node-gyp-build "~4.1.0" + +levelup@4.4.0, levelup@^4.3.2: + version "4.4.0" + resolved "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz" + integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== + dependencies: + deferred-leveldown "~5.3.0" + level-errors "~2.0.0" + level-iterator-stream "~4.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + levn@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -1042,109 +1832,236 @@ levn@^0.4.1: levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + +load-module@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/load-module/-/load-module-4.2.1.tgz#3b596a4ddee52c59106d38160aa631a0ded68867" + integrity sha512-Sbfg6R4LjvyThJpqUoADHMjyoI2+cL4msbCQeZ9kkY/CqP/TT2938eftKm7x4I2gd4/A+DEe6nePkbfWYbXwSw== + dependencies: + array-back "^6.2.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 sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isarguments@3.1.0, lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + lodash.merge@^4.6.2: version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.noop@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" + integrity sha512-TmYdmu/pebrdTIBDK/FDx9Bmfzs9x0sZG6QIJuMDTqEPfeciLcN13ij+cOd0i9vwJfBtbG9UQ+C7MkXgYxrIJg== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash.pick@^4.0.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz" + integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== + lodash.truncate@^4.4.2: version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= -lodash@^4.17.19, lodash@^4.17.21: +lodash@4.17.21, lodash@^4.14.0, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -lookpath@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/lookpath/-/lookpath-1.2.2.tgz#bddcd1440b6643e07495138376d43aed38bcd454" - integrity sha512-k2Gmn8iV6qdME3ztZC2spubmQISimFOPLuQKiPaLcVdRz0IpdxrNClVepMlyTJlhodm/zG/VfbkWERm3kUIh+Q== +lookpath@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/lookpath/-/lookpath-1.1.0.tgz#932d68371a2f0b4a5644f03d6a2b4728edba96d2" + integrity sha512-B9NM7XpVfkyWqfOBI/UW0kVhGw7pJztsduch+1wkbYDi90mYK6/InFul3lG0hYko/VEcVMARVBJ5daFRc5aKCw== lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" +ltgt@2.2.1, ltgt@^2.1.2: + version "2.2.1" + resolved "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz" + integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== + +make-dir@^3.1.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" + md5@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + resolved "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz" integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== dependencies: charenc "0.0.2" crypt "0.0.2" is-buffer "~1.1.6" -merge2@^1.3.0: +merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.4: version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== dependencies: braces "^3.0.1" picomatch "^2.2.3" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== mimic-response@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz" integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== +minimatch@^3.0.3, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimatch@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== +minipass@^3.0.0: + version "3.3.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz" + integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.3: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== multistream@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/multistream/-/multistream-4.1.0.tgz#7bf00dfd119556fbc153cff3de4c6d477909f5a8" + resolved "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz" integrity sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw== dependencies: once "^1.4.0" @@ -1152,41 +2069,86 @@ multistream@^4.1.0: mute-stream@0.0.8: version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== napi-build-utils@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -node-abi@^2.7.0: +ndjson@^1.4.3: + version "1.5.0" + resolved "https://registry.npmjs.org/ndjson/-/ndjson-1.5.0.tgz" + integrity sha512-hUPLuaziboGjNF7wHngkgVc0FOclR8dDk/HfEvTtDr/iUrqBWiRcRSTK3/nLOqKH33th714BrMmTPtObI9gZxQ== + dependencies: + json-stringify-safe "^5.0.1" + minimist "^1.2.0" + split2 "^2.1.0" + through2 "^2.0.3" + +node-abi@^2.21.0: version "2.30.1" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.30.1.tgz#c437d4b1fe0e285aaf290d45b45d4d7afedac4cf" integrity sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w== dependencies: semver "^5.4.1" -node-fetch@^2.6.1: - version "2.6.6" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" - integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== +node-addon-api@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-fetch@2, node-fetch@2.6.7, node-fetch@^2.6.6, node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -noop-logger@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" - integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= +node-fetch@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + +node-forge@^0.7.1: + version "0.7.6" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" + integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== + +node-gyp-build@~4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz" + integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== + +noms@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" + integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== + dependencies: + inherits "^2.0.1" + readable-stream "~1.0.31" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" npmlog@^4.0.1: version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" @@ -1194,33 +2156,53 @@ npmlog@^4.0.1: gauge "~2.7.3" set-blocking "~2.0.0" +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -object-assign@^4.1.0: +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +oauth@0.9.x, oauth@^0.9.15: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA== + +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" onetime@^5.1.0: version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" optionator@^0.8.1: version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -1232,7 +2214,7 @@ optionator@^0.8.1: optionator@^0.9.1: version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: deep-is "^0.1.3" @@ -1242,100 +2224,183 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" -ora@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - os-tmpdir@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= p-is-promise@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-3.0.0.tgz#58e78c7dfe2e163cf2a04ff869e7c1dba64a5971" + resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz" integrity sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ== +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" +passport-google-auth@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/passport-google-auth/-/passport-google-auth-1.0.2.tgz#8b300b5aa442ef433de1d832ed3112877d0b2938" + integrity sha512-cfAqna6jZLyMEwUdd4PIwAh2mQKQVEDAaRIaom1pG6h4x4Gwjllf/Jflt3TkR1Sen5Rkvr3l7kSXCWE1EKkh8g== + dependencies: + googleapis "^16.0.0" + passport-strategy "1.x" + +passport-google-oauth1@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz#af74a803df51ec646f66a44d82282be6f108e0cc" + integrity sha512-qpCEhuflJgYrdg5zZIpAq/K3gTqa1CtHjbubsEsidIdpBPLkEVq6tB1I8kBNcH89RdSiYbnKpCBXAZXX/dtx1Q== + dependencies: + passport-oauth1 "1.x.x" + +passport-google-oauth20@2.x.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz#0d241b2d21ebd3dc7f2b60669ec4d587e3a674ef" + integrity sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ== + dependencies: + passport-oauth2 "1.x.x" + +passport-google-oauth@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz#f6eb4bc96dd6c16ec0ecfdf4e05ec48ca54d4dae" + integrity sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA== + dependencies: + passport-google-oauth1 "1.x.x" + passport-google-oauth20 "2.x.x" + +passport-jwt@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + integrity sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg== + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + +passport-local@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" + integrity sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow== + dependencies: + passport-strategy "1.x.x" + +passport-oauth1@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.2.0.tgz#5229d431781bf5b265bec86ce9a9cce58a756cf9" + integrity sha512-Sv2YWodC6jN12M/OXwmR4BIXeeIHjjbwYTQw4kS6tHK4zYzSEpxBgSJJnknBjICA5cj0ju3FSnG1XmHgIhYnLg== + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + utils-merge "1.x.x" + +passport-oauth2-refresh@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/passport-oauth2-refresh/-/passport-oauth2-refresh-2.1.0.tgz#c31cd133826383f5539d16ad8ab4f35ca73ce4a4" + integrity sha512-4ML7ooCESCqiTgdDBzNUFTBcPR8zQq9iM6eppEUGMMvLdsjqRL93jKwWm4Az3OJcI+Q2eIVyI8sVRcPFvxcF/A== + +passport-oauth2@1.x.x: + version "1.6.1" + resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.1.tgz#c5aee8f849ce8bd436c7f81d904a3cd1666f181b" + integrity sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ== + dependencies: + base64url "3.x.x" + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + +passport-strategy@1.x, passport-strategy@1.x.x, passport-strategy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== + +passport@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" + integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-key@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: +path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-type@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + picomatch@^2.2.3: version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== -pkg-fetch@3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/pkg-fetch/-/pkg-fetch-3.2.4.tgz#5372734b12167d4bacd872be348217461b517390" - integrity sha512-ewUD26GP86/8+Fu93zrb30CpJjKOtT4maSgm4SwTX9Ujy1pfdUdv+1PubsY9tTJES0iBYItAtqbfkf7Wu5LV9w== +pkg-fetch@3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/pkg-fetch/-/pkg-fetch-3.4.1.tgz#be68bb9f7fdb0f6ed995abc518ab2e35aa64d2fd" + integrity sha512-fS4cdayCa1r4jHkOKGPJKnS9PEs6OWZst+s+m0+CmhmPZObMnxoRnf9T9yUWl+lzM2b5aJF7cnQIySCT7Hq8Dg== dependencies: - chalk "^4.1.0" + chalk "^4.1.2" fs-extra "^9.1.0" https-proxy-agent "^5.0.0" - node-fetch "^2.6.1" + node-fetch "^2.6.6" progress "^2.0.3" semver "^7.3.5" + tar-fs "^2.1.1" yargs "^16.2.0" -pkg@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/pkg/-/pkg-5.4.1.tgz#4d824e42c454f32131e471d7cd8d14bfdb3e1c4c" - integrity sha512-iJs3W6MCgeZ4MrH7iZtX6HTqsNzoh2U9rGILL3eOLbQFV43U8WPAzrqRK7cBQGuHx38UXxcGT6G/2yDl/GveRg== +pkg@5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/pkg/-/pkg-5.7.0.tgz#6422df05e8aa147764be6ef912921d0fa719ea95" + integrity sha512-PTiAjNq/CGAtK5qUBR6pjheqnipTFjeecgSgIKEcAOJA4GpmZeOZC8pMOoT0rfes5vHsmcFo7wbSRTAmXQurrg== dependencies: - "@babel/parser" "7.13.13" - "@babel/types" "7.13.12" - chalk "^4.1.0" + "@babel/parser" "7.17.10" + "@babel/types" "7.17.10" + chalk "^4.1.2" escodegen "^2.0.0" fs-extra "^9.1.0" - globby "^11.0.3" + globby "^11.1.0" into-stream "^6.0.0" - minimist "^1.2.5" + is-core-module "2.9.0" + minimist "^1.2.6" multistream "^4.1.0" - pkg-fetch "3.2.4" - prebuild-install "6.0.1" - progress "^2.0.3" - resolve "^1.20.0" + pkg-fetch "3.4.1" + prebuild-install "6.1.4" + resolve "^1.22.0" stream-meter "^1.0.4" - tslib "2.1.0" posthog-node@1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-1.0.7.tgz#a7a9525eebff23312117e57cff3ddac82afb2262" + resolved "https://registry.npmjs.org/posthog-node/-/posthog-node-1.0.7.tgz" integrity sha512-KTCwyU+PU1eAQtjy5ZSJ47mrxv2d/mMkxo+vvV5c+YqfE4mBAY1UPEPMv1nElb5Vq0UnxvyQXaUnOn8d8Xr6Eg== dependencies: axios "^0.21.1" @@ -1347,10 +2412,178 @@ posthog-node@1.0.7: remove-trailing-slash "^0.1.1" uuid "^8.3.2" -prebuild-install@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.0.1.tgz#5902172f7a40eb67305b96c2a695db32636ee26d" - integrity sha512-7GOJrLuow8yeiyv75rmvZyeMGzl8mdEX5gY69d6a6bHWmiPevwqFw+tQavhK0EYMaSg3/KD24cWqeQv1EWsqDQ== +posthog-node@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-1.3.0.tgz#804ed2f213a2f05253f798bf9569d55a9cad94f7" + integrity sha512-2+VhqiY/rKIqKIXyvemBFHbeijHE25sP7eKltnqcFqAssUE6+sX6vusN9A4luzToOqHQkUZexiCKxvuGagh7JA== + dependencies: + axios "0.24.0" + axios-retry "^3.1.9" + component-type "^1.2.1" + join-component "^1.1.0" + md5 "^2.3.0" + ms "^2.1.3" + remove-trailing-slash "^0.1.1" + uuid "^8.3.2" + +pouch-stream@^0.4.0: + version "0.4.1" + resolved "https://registry.npmjs.org/pouch-stream/-/pouch-stream-0.4.1.tgz" + integrity sha512-RAWFhsGDbG4xZQpvrrQlhrITVUNVCKmglfe5WWDnJaDf1u9DMaRLHv//m65tBZevuo4QTGjwcyggwYxd7AGLsg== + dependencies: + inherits "^2.0.1" + readable-stream "^1.0.27-1" + +pouchdb-abstract-mapreduce@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-7.2.2.tgz#dd1b10a83f8d24361dce9aaaab054614b39f766f" + integrity sha512-7HWN/2yV2JkwMnGnlp84lGvFtnm0Q55NiBUdbBcaT810+clCGKvhssBCrXnmwShD1SXTwT83aszsgiSfW+SnBA== + dependencies: + pouchdb-binary-utils "7.2.2" + pouchdb-collate "7.2.2" + pouchdb-collections "7.2.2" + pouchdb-errors "7.2.2" + pouchdb-fetch "7.2.2" + pouchdb-mapreduce-utils "7.2.2" + pouchdb-md5 "7.2.2" + pouchdb-utils "7.2.2" + +pouchdb-binary-utils@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-7.2.2.tgz#0690b348052c543b1e67f032f47092ca82bcb10e" + integrity sha512-shacxlmyHbUrNfE6FGYpfyAJx7Q0m91lDdEAaPoKZM3SzAmbtB1i+OaDNtYFztXjJl16yeudkDb3xOeokVL3Qw== + dependencies: + buffer-from "1.1.1" + +pouchdb-collate@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-7.2.2.tgz#fc261f5ef837c437e3445fb0abc3f125d982c37c" + integrity sha512-/SMY9GGasslknivWlCVwXMRMnQ8myKHs4WryQ5535nq1Wj/ehpqWloMwxEQGvZE1Sda3LOm7/5HwLTcB8Our+w== + +pouchdb-collections@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-7.2.2.tgz#aeed77f33322429e3f59d59ea233b48ff0e68572" + integrity sha512-6O9zyAYlp3UdtfneiMYuOCWdUCQNo2bgdjvNsMSacQX+3g8WvIoFQCYJjZZCpTttQGb+MHeRMr8m2U95lhJTew== + +pouchdb-errors@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-7.2.2.tgz#80d811d65c766c9d20b755c6e6cc123f8c3c4792" + integrity sha512-6GQsiWc+7uPfgEHeavG+7wuzH3JZW29Dnrvz8eVbDFE50kVFxNDVm3EkYHskvo5isG7/IkOx7PV7RPTA3keG3g== + dependencies: + inherits "2.0.4" + +pouchdb-fetch@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-fetch/-/pouchdb-fetch-7.2.2.tgz#492791236d60c899d7e9973f9aca0d7b9cc02230" + integrity sha512-lUHmaG6U3zjdMkh8Vob9GvEiRGwJfXKE02aZfjiVQgew+9SLkuOxNw3y2q4d1B6mBd273y1k2Lm0IAziRNxQnA== + dependencies: + abort-controller "3.0.0" + fetch-cookie "0.10.1" + node-fetch "2.6.0" + +pouchdb-find@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-find/-/pouchdb-find-7.2.2.tgz#1227afdd761812d508fe0794b3e904518a721089" + integrity sha512-BmFeFVQ0kHmDehvJxNZl9OmIztCjPlZlVSdpijuFbk/Fi1EFPU1BAv3kLC+6DhZuOqU/BCoaUBY9sn66pPY2ag== + dependencies: + pouchdb-abstract-mapreduce "7.2.2" + pouchdb-collate "7.2.2" + pouchdb-errors "7.2.2" + pouchdb-fetch "7.2.2" + pouchdb-md5 "7.2.2" + pouchdb-selector-core "7.2.2" + pouchdb-utils "7.2.2" + +pouchdb-mapreduce-utils@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-7.2.2.tgz#13a46a3cc2a3f3b8e24861da26966904f2963146" + integrity sha512-rAllb73hIkU8rU2LJNbzlcj91KuulpwQu804/F6xF3fhZKC/4JQMClahk+N/+VATkpmLxp1zWmvmgdlwVU4HtQ== + dependencies: + argsarray "0.0.1" + inherits "2.0.4" + pouchdb-collections "7.2.2" + pouchdb-utils "7.2.2" + +pouchdb-md5@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-7.2.2.tgz#415401acc5a844112d765bd1fb4e5d9f38fb0838" + integrity sha512-c/RvLp2oSh8PLAWU5vFBnp6ejJABIdKqboZwRRUrWcfGDf+oyX8RgmJFlYlzMMOh4XQLUT1IoaDV8cwlsuryZw== + dependencies: + pouchdb-binary-utils "7.2.2" + spark-md5 "3.0.1" + +pouchdb-promise@^6.0.4: + version "6.4.3" + resolved "https://registry.npmjs.org/pouchdb-promise/-/pouchdb-promise-6.4.3.tgz" + integrity sha512-ruJaSFXwzsxRHQfwNHjQfsj58LBOY1RzGzde4PM5CWINZwFjCQAhZwfMrch2o/0oZT6d+Xtt0HTWhq35p3b0qw== + dependencies: + lie "3.1.1" + +pouchdb-replication-stream@1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.9.tgz#aa4fa5d8f52df4825392f18e07c7e11acffc650a" + integrity sha512-hM8XRBfamTTUwRhKwLS/jSNouBhn9R/4ugdHNRD1EvJzwV8iImh6sDYbCU9PGuznjyOjXz6vpFRzKeI2KYfwnQ== + dependencies: + argsarray "0.0.1" + inherits "^2.0.3" + lodash.pick "^4.0.0" + ndjson "^1.4.3" + pouch-stream "^0.4.0" + pouchdb-promise "^6.0.4" + through2 "^2.0.0" + +pouchdb-selector-core@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-7.2.2.tgz#264d7436a8c8ac3801f39960e79875ef7f3879a0" + integrity sha512-XYKCNv9oiNmSXV5+CgR9pkEkTFqxQGWplnVhO3W9P154H08lU0ZoNH02+uf+NjZ2kjse7Q1fxV4r401LEcGMMg== + dependencies: + pouchdb-collate "7.2.2" + pouchdb-utils "7.2.2" + +pouchdb-utils@7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-7.2.2.tgz#c17c4788f1d052b0daf4ef8797bbc4aaa3945aa4" + integrity sha512-XmeM5ioB4KCfyB2MGZXu1Bb2xkElNwF1qG+zVFbQsKQij0zvepdOUfGuWvLRHxTOmt4muIuSOmWZObZa3NOgzQ== + dependencies: + argsarray "0.0.1" + clone-buffer "1.0.0" + immediate "3.3.0" + inherits "2.0.4" + pouchdb-collections "7.2.2" + pouchdb-errors "7.2.2" + pouchdb-md5 "7.2.2" + uuid "8.1.0" + +pouchdb@7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-7.3.0.tgz#440fbef12dfd8f9002320802528665e883a3b7f8" + integrity sha512-OwsIQGXsfx3TrU1pLruj6PGSwFH+h5k4hGNxFkZ76Um7/ZI8F5TzUHFrpldVVIhfXYi2vP31q0q7ot1FSLFYOw== + dependencies: + abort-controller "3.0.0" + argsarray "0.0.1" + buffer-from "1.1.2" + clone-buffer "1.0.0" + double-ended-queue "2.1.0-0" + fetch-cookie "0.11.0" + immediate "3.3.0" + inherits "2.0.4" + level "6.0.1" + level-codec "9.0.2" + level-write-stream "1.0.0" + leveldown "5.6.0" + levelup "4.4.0" + ltgt "2.2.1" + node-fetch "2.6.7" + readable-stream "1.1.14" + spark-md5 "3.0.2" + through2 "3.0.2" + uuid "8.3.2" + vuvuzela "1.0.3" + +prebuild-install@6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.1.4.tgz#ae3c0142ad611d58570b89af4986088a4937e00f" + integrity sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ== dependencies: detect-libc "^1.0.3" expand-template "^2.0.3" @@ -1358,70 +2591,97 @@ prebuild-install@6.0.1: minimist "^1.2.3" mkdirp-classic "^0.5.3" napi-build-utils "^1.0.1" - node-abi "^2.7.0" - noop-logger "^0.1.1" + node-abi "^2.21.0" npmlog "^4.0.1" pump "^3.0.0" rc "^1.2.7" simple-get "^3.0.3" tar-fs "^2.0.0" tunnel-agent "^0.6.0" - which-pm-runs "^1.0.0" prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +printj@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" + integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== + process-nextick-args@~2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== progress@^2.0.0, progress@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + +psl@^1.1.28: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + pump@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0: +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== + +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qs@~6.5.2: + version "6.5.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== + queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -randombytes@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" - integrity sha1-Z0yZdgkBw8QRJ3GjHlIdw0nMCew= - -randomstring@^1.1.5: - version "1.2.1" - resolved "https://registry.yarnpkg.com/randomstring/-/randomstring-1.2.1.tgz#71cd3cda24ad1b7e0b65286b3aa5c10853019349" - integrity sha512-eMnfell9XuU3jfCx3f4xCaFAt0YMFPZhx9R3PSStmLarDKg5j5vivqKhf/8pvG+VX/YkxsckHK/VPUrKa5V07A== +randomstring@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/randomstring/-/randomstring-1.1.5.tgz#6df0628f75cbd5932930d9fe3ab4e956a18518c3" + integrity sha512-JNZlJOCHjifKhZszDT8UYYkcIUgpJyGDobFMOBPic2/9h+esM0m1JzySt8nk4PjrxQeeYkNzdVP3XPpQOCzjZA== dependencies: array-uniq "1.0.2" - randombytes "2.0.3" rc@^1.2.7: version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" @@ -1429,9 +2689,28 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.4: +readable-stream@1.1.14, readable-stream@^1.0.27-1: + version "1.1.14" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz" + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +"readable-stream@2 || 3", readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@~2.3.6: version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" @@ -1442,56 +2721,136 @@ readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.4: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, 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== +readable-stream@~0.0.2: + version "0.0.4" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-0.0.4.tgz" + integrity sha512-azrivNydKRYt7zwLV5wWUK7YzKTWs3q87xSmY6DlHapPrCvaT6ZrukvM5erV+yCSSPmZT8zkSdttOHQpWWm9zw== + +readable-stream@~1.0.31: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + +redlock@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/redlock/-/redlock-4.2.0.tgz#c26590768559afd5fff76aa1133c94b411ff4f5f" + integrity sha512-j+oQlG+dOwcetUt2WJWttu4CZVeRzUrcVcISFmEmfyuwCVSJ93rDT7YSgg7H7rnxwoRyk/jU46kycVka5tW7jA== + dependencies: + bluebird "^3.7.2" + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== regenerator-runtime@^0.13.4: version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== regexpp@^3.1.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== remove-trailing-slash@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d" + resolved "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz" integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== +renamer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/renamer/-/renamer-4.0.0.tgz#12e96979f2fec0f0ce31fa1c6384d668bc80f648" + integrity sha512-yurufcXxbJfFBVAUoByNyDVH811zTZ/MrKo6gUH8pHGeAmdK7J5egj2lSNe57HuVIvnVzSalzeVGu8pi8UHGxg== + dependencies: + array-back "^6.2.0" + chalk "^4.1.2" + command-line-args "^5.2.0" + command-line-usage "^6.1.1" + current-module-paths "^1.1.0" + fast-diff "^1.2.0" + file-set "^5.1.2" + global-dirs "^3.0.0" + load-module "^4.2.1" + printj "^1.3.0" + stream-read-all "^3.0.1" + typical "^7.1.1" + +request@^2.72.0, request@^2.74.0, request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-from-string@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== +resolve@^1.22.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" restore-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== dependencies: onetime "^5.1.0" @@ -1499,7 +2858,7 @@ restore-cursor@^3.1.0: reusify@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@^3.0.2: @@ -1511,80 +2870,112 @@ rimraf@^3.0.2: run-async@^2.4.0: version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== run-parallel@^1.1.9: version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" -rxjs@^7.2.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68" - integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w== +rxjs@^6.6.6: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: - tslib "~2.1.0" + tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -semver@^5.4.1: +sanitize-s3-objectkey@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" + integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ== + +sax@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== + +sax@>=0.1.1, sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +semver@7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +semver@^5.4.1, semver@^5.6.0: version "5.7.1" 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.2.1, semver@^7.3.5: version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -set-blocking@~2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shimmer@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" + integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.5" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz" integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== simple-concat@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== simple-get@^3.0.3: version "3.1.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55" + resolved "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz" integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== dependencies: decompress-response "^4.2.0" @@ -1593,12 +2984,12 @@ simple-get@^3.0.3: slash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== slice-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: ansi-styles "^4.0.0" @@ -1607,24 +2998,76 @@ slice-ansi@^4.0.0: source-map@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spark-md5@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.1.tgz#83a0e255734f2ab4e5c466e5a2cfc9ba2aa2124d" + integrity sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig== + +spark-md5@3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== + +split2@^2.1.0: + version "2.2.0" + resolved "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz" + integrity sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw== + dependencies: + through2 "^2.0.2" + sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +sshpk@^1.7.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + +step@0.0.x: + version "0.0.6" + resolved "https://registry.yarnpkg.com/step/-/step-0.0.6.tgz#143e7849a5d7d3f4a088fe29af94915216eeede2" + integrity sha512-qSSeQinUJk2w38vUFobjFoE307GqsozMC8VisOCkJLpklvKPT0ptPHwWOrENoag8rgLudvTkfP3bancwP93/Jw== + stream-meter@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/stream-meter/-/stream-meter-1.0.4.tgz#52af95aa5ea760a2491716704dbff90f73afdd1d" + resolved "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz" integrity sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0= dependencies: readable-stream "^2.1.4" +stream-read-all@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/stream-read-all/-/stream-read-all-3.0.1.tgz#60762ae45e61d93ba0978cda7f3913790052ad96" + integrity sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A== + +string-template@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" + integrity sha512-SLqR3GBUXuoPP5MmYtD7ompvXiG87QjT6lzOszyXjTM86Uu7At7vNnt2xgyTLq5o9T4IxTYFyGxcULqpsmsfdg== + string-width@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" @@ -1633,7 +3076,7 @@ string-width@^1.0.1: "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -1642,59 +3085,79 @@ string-width@^1.0.1: string_decoder@^1.1.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "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== + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + table@^6.0.9: version "6.7.3" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.3.tgz#255388439715a738391bd2ee4cbca89a4d05a9b7" + resolved "https://registry.npmjs.org/table/-/table-6.7.3.tgz" integrity sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw== dependencies: ajv "^8.0.1" @@ -1703,7 +3166,7 @@ table@^6.0.9: string-width "^4.2.3" strip-ansi "^6.0.1" -tar-fs@^2.0.0: +tar-fs@2.1.1, tar-fs@^2.0.0, tar-fs@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -1715,7 +3178,7 @@ tar-fs@^2.0.0: tar-stream@^2.1.4: version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: bl "^4.0.3" @@ -1724,136 +3187,254 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" +tar@6.1.11, tar@^6.1.11: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + text-table@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +through2@3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + +through2@^2.0.0, through2@^2.0.1, through2@^2.0.2, through2@^2.0.3: + version "2.0.5" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + through@^2.3.6: version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= tmp@^0.0.33: version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -tslib@2.1.0, tslib@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" - integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tunnel-agent@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" type-fest@^0.20.2: version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +typical@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/typical/-/typical-7.1.1.tgz#ba177ab7ab103b78534463ffa4c0c9754523ac1f" + integrity sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA== + +uid2@0.0.x: + version "0.0.4" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.4.tgz#033f3b1d5d32505f5ce5f888b9f3b667123c0a44" + integrity sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA== + +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + universalify@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + integrity sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ== + dependencies: + punycode "1.3.2" + querystring "0.2.0" + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@^8.3.2: +utils-merge@1.x.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +uuid@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d" + integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== + +uuid@8.3.2, uuid@^8.3.2: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + v8-compile-cache@^2.0.3: version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== dependencies: - defaults "^1.0.3" + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vuvuzela@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz" + integrity sha512-Tm7jR1xTzBbPW+6y1tknKiEhz04Wf/1iZkcTJjSFcpNko43+dFW6+OOeQe9taJIug3NdfUAjFKgUSyQrIKaDvQ== + +webfinger@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/webfinger/-/webfinger-0.4.2.tgz#3477a6d97799461896039fcffc650b73468ee76d" + integrity sha512-PvvQ/k74HkC3q5G7bGu4VYeKDt3ePZMzT5qFPtEnOL8eyIU1/06OtDn9X5vlkQ23BlegA3eN89rDLiYUife3xQ== + dependencies: + step "0.0.x" + xml2js "0.1.x" webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which-pm-runs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" - integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= - which@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" -wide-align@^1.1.0: +wide-align@^1.1.0, wide-align@^1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== @@ -1862,12 +3443,20 @@ wide-align@^1.1.0: word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" + wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -1876,32 +3465,59 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-stream@~0.4.3: + version "0.4.3" + resolved "https://registry.npmjs.org/write-stream/-/write-stream-0.4.3.tgz" + integrity sha512-IJrvkhbAnj89W/GAVdVgbnPiVw5Ntg/B4tc/MUCIEwj/g6JIww1DWJyB/yBMT3yw2/TkT6IUZ0+IYef3flEw8A== + dependencies: + readable-stream "~0.0.2" + +xml2js@0.1.x: + version "0.1.14" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c" + integrity sha512-pbdws4PPPNc1HPluSUKamY4GWMk592K7qwcj6BExbVOhhubub8+pMda/ql68b6L3luZs/OGjGSB5goV7SnmgnA== + dependencies: + sax ">=0.1.1" + +xml2js@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ== + +xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - yargs-parser@^20.2.2: version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^16.2.0: +yargs@^16.1.0, yargs@^16.2.0: version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" @@ -1911,3 +3527,8 @@ yargs@^16.2.0: string-width "^4.2.0" y18n "^5.0.5" yargs-parser "^20.2.2" + +zlib@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/zlib/-/zlib-1.0.5.tgz#6e7c972fc371c645a6afb03ab14769def114fcc0" + integrity sha512-40fpE2II+Cd3k8HWTWONfeKE2jL+P42iWJ1zzps5W51qcTsOUKM5Q5m2PFb0CLxlmFAaUuUdJGc3OfZy947v0w== diff --git a/packages/client/manifest.json b/packages/client/manifest.json index a47a89f0e3..cfed5b65f7 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -3509,17 +3509,18 @@ }, { "type": "boolean", - "label": "Show button", + "label": "Use button for click action", "key": "showButton" }, { "type": "text", "key": "buttonText", - "label": "Button text" + "label": "Button text", + "dependsOn": "showButton" }, { "type": "event", - "label": "Button action", + "label": "Click action", "key": "buttonOnClick" } ] @@ -3841,18 +3842,19 @@ }, { "type": "boolean", - "label": "Show button", + "label": "Use button for click action", "key": "showCardButton" }, { "type": "text", "key": "cardButtonText", "label": "Button text", - "nested": true + "nested": true, + "dependsOn": "showCardButton" }, { "type": "event", - "label": "Button action", + "label": "Click action", "key": "cardButtonOnClick", "nested": true } diff --git a/packages/client/package.json b/packages/client/package.json index 06483fc8c7..dfab542d39 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^1.1.31", - "@budibase/frontend-core": "^1.1.31", - "@budibase/string-templates": "^1.1.31", + "@budibase/bbui": "1.1.33-alpha.0", + "@budibase/frontend-core": "1.1.33-alpha.0", + "@budibase/string-templates": "1.1.33-alpha.0", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", @@ -39,7 +39,7 @@ "sanitize-html": "^2.7.0", "screenfull": "^6.0.1", "shortid": "^2.2.15", - "svelte": "^3.38.2", + "svelte": "^3.49.0", "svelte-apexcharts": "^1.0.2", "svelte-flatpickr": "^3.1.0", "svelte-spa-router": "^3.0.5" diff --git a/packages/client/src/api/api.js b/packages/client/src/api/api.js index b96ad9c9e7..563126fdd0 100644 --- a/packages/client/src/api/api.js +++ b/packages/client/src/api/api.js @@ -58,7 +58,16 @@ export const API = createAPIClient({ } } if (!ignore) { - notificationStore.actions.error(message) + const validationErrors = error?.json?.validationErrors + if (validationErrors) { + for (let field in validationErrors) { + notificationStore.actions.error( + `${field} ${validationErrors[field]}` + ) + } + } else { + notificationStore.actions.error(message) + } } } diff --git a/packages/client/src/components/app/SpectrumCard.svelte b/packages/client/src/components/app/SpectrumCard.svelte index 4b4f9d62f2..3b2fe44f4e 100644 --- a/packages/client/src/components/app/SpectrumCard.svelte +++ b/packages/client/src/components/app/SpectrumCard.svelte @@ -19,9 +19,10 @@ const handleLink = e => { if (!linkURL) { - return + return false } e.preventDefault() + e.stopPropagation() routeStore.actions.navigate(linkURL, linkPeek) } @@ -32,6 +33,8 @@ tabindex="0" role="figure" class:horizontal + class:clickable={buttonOnClick && !showButton} + on:click={showButton ? null : buttonOnClick} > {#if imageURL} {/if}
@@ -81,6 +86,11 @@ flex-direction: column; justify-content: flex-start; align-items: stretch; + transition: border-color 130ms ease-out; + } + .spectrum-Card.clickable:hover { + cursor: pointer; + border-color: var(--spectrum-global-color-gray-500) !important; } .spectrum-Card.horizontal { flex-direction: row; @@ -90,7 +100,7 @@ padding: var(--spectrum-global-dimension-size-50) 0; } .spectrum-Card-title.link { - transition: color 130ms ease-in-out; + transition: color 130ms ease-out; } .spectrum-Card-title.link:hover { cursor: pointer; diff --git a/packages/client/src/components/app/blocks/CardsBlock.svelte b/packages/client/src/components/app/blocks/CardsBlock.svelte index f6aed54760..a13364833a 100644 --- a/packages/client/src/components/app/blocks/CardsBlock.svelte +++ b/packages/client/src/components/app/blocks/CardsBlock.svelte @@ -4,6 +4,7 @@ import BlockComponent from "components/BlockComponent.svelte" import { Heading } from "@budibase/bbui" import { makePropSafe as safe } from "@budibase/string-templates" + import { enrichSearchColumns, enrichFilter } from "utils/blocks.js" export let title export let dataSource @@ -33,14 +34,6 @@ const { fetchDatasourceSchema, styleable } = getContext("sdk") const context = getContext("context") const component = getContext("component") - const schemaComponentMap = { - string: "stringfield", - options: "optionsfield", - number: "numberfield", - datetime: "datetimefield", - boolean: "booleanfield", - formula: "stringfield", - } let formId let dataProviderId @@ -68,39 +61,6 @@ }, ] - // Enrich the default filter with the specified search fields - const enrichFilter = (filter, columns, formId) => { - let enrichedFilter = [...(filter || [])] - columns?.forEach(column => { - const safePath = column.name.split(".").map(safe).join(".") - enrichedFilter.push({ - field: column.name, - operator: column.type === "string" ? "string" : "equal", - type: column.type, - valueType: "Binding", - value: `{{ ${safe(formId)}.${safePath} }}`, - }) - }) - return enrichedFilter - } - - // Determine data types for search fields and only use those that are valid - const enrichSearchColumns = (searchColumns, schema) => { - let enrichedColumns = [] - searchColumns?.forEach(column => { - const schemaType = schema?.[column]?.type - const componentType = schemaComponentMap[schemaType] - if (componentType) { - enrichedColumns.push({ - name: column, - componentType, - type: schemaType, - }) - } - }) - return enrichedColumns.slice(0, 5) - } - // Builds a full details page URL for the card title const buildFullCardUrl = (link, url, repeaterId, linkColumn) => { if (!link || !url || !repeaterId) { diff --git a/packages/client/src/components/app/blocks/TableBlock.svelte b/packages/client/src/components/app/blocks/TableBlock.svelte index 4ae169ca72..e67124fc4f 100644 --- a/packages/client/src/components/app/blocks/TableBlock.svelte +++ b/packages/client/src/components/app/blocks/TableBlock.svelte @@ -4,6 +4,7 @@ import BlockComponent from "components/BlockComponent.svelte" import { Heading } from "@budibase/bbui" import { makePropSafe as safe } from "@budibase/string-templates" + import { enrichSearchColumns, enrichFilter } from "utils/blocks.js" export let title export let dataSource @@ -31,14 +32,6 @@ const { fetchDatasourceSchema, styleable } = getContext("sdk") const context = getContext("context") const component = getContext("component") - const schemaComponentMap = { - string: "stringfield", - options: "optionsfield", - number: "numberfield", - datetime: "datetimefield", - boolean: "booleanfield", - formula: "stringfield", - } let formId let dataProviderId @@ -58,40 +51,6 @@ }, ] - // Enrich the default filter with the specified search fields - const enrichFilter = (filter, columns, formId) => { - let enrichedFilter = [...(filter || [])] - columns?.forEach(column => { - const safePath = column.name.split(".").map(safe).join(".") - const stringType = column.type === "string" || column.type === "formula" - enrichedFilter.push({ - field: column.name, - type: column.type, - operator: stringType ? "string" : "equal", - valueType: "Binding", - value: `{{ ${safe(formId)}.${safePath} }}`, - }) - }) - return enrichedFilter - } - - // Determine data types for search fields and only use those that are valid - const enrichSearchColumns = (searchColumns, schema) => { - let enrichedColumns = [] - searchColumns?.forEach(column => { - const schemaType = schema?.[column]?.type - const componentType = schemaComponentMap[schemaType] - if (componentType) { - enrichedColumns.push({ - name: column, - componentType, - type: schemaType, - }) - } - }) - return enrichedColumns.slice(0, 5) - } - // Load the datasource schema so we can determine column types const fetchSchema = async dataSource => { if (dataSource) { @@ -109,7 +68,7 @@ {#if title || enrichedSearchColumns?.length || showTitleButton}
diff --git a/packages/client/src/components/app/forms/Form.svelte b/packages/client/src/components/app/forms/Form.svelte index a274fb24f0..320fc712aa 100644 --- a/packages/client/src/components/app/forms/Form.svelte +++ b/packages/client/src/components/app/forms/Form.svelte @@ -13,6 +13,10 @@ // for fields rendered in things like search blocks. export let disableValidation = false + // Not exposed as a builder setting. Used internally to allow searching on + // auto columns. + export let editAutoColumns = false + const context = getContext("context") const { API, fetchDatasourceSchema } = getContext("sdk") @@ -107,6 +111,7 @@ {table} {initialValues} {disableValidation} + {editAutoColumns} > diff --git a/packages/client/src/components/app/forms/InnerForm.svelte b/packages/client/src/components/app/forms/InnerForm.svelte index 752bc9a2eb..554085ba91 100644 --- a/packages/client/src/components/app/forms/InnerForm.svelte +++ b/packages/client/src/components/app/forms/InnerForm.svelte @@ -11,6 +11,7 @@ export let schema export let table export let disableValidation = false + export let editAutoColumns = false const component = getContext("component") const { styleable, Provider, ActionTypes } = getContext("sdk") @@ -183,7 +184,8 @@ fieldId, value: initialValue, error: initialError, - disabled: disabled || fieldDisabled || isAutoColumn, + disabled: + disabled || fieldDisabled || (isAutoColumn && !editAutoColumns), defaultValue, validator, lastUpdate: Date.now(), @@ -202,14 +204,11 @@ return fieldInfo }, - validate: (onlyCurrentStep = false) => { + validate: () => { let valid = true let validationFields = fields - // Reduce fields to only the current step if required - if (onlyCurrentStep) { - validationFields = fields.filter(f => get(f).step === get(currentStep)) - } + validationFields = fields.filter(f => get(f).step === get(currentStep)) // Validate fields and check if any are invalid validationFields.forEach(field => { diff --git a/packages/client/src/components/overlay/NotificationDisplay.svelte b/packages/client/src/components/overlay/NotificationDisplay.svelte index 667f706ff2..669fa41a1d 100644 --- a/packages/client/src/components/overlay/NotificationDisplay.svelte +++ b/packages/client/src/components/overlay/NotificationDisplay.svelte @@ -6,7 +6,7 @@
{#if $notificationStore} - {#key $notificationStore.id} + {#each $notificationStore as { type, icon, message, id, dismissable } (id)}
notificationStore.actions.dismiss(id)} />
- {/key} + {/each} {/if}
@@ -31,6 +31,7 @@ .notifications { position: fixed; top: 20px; + bottom: 40px; left: 0; right: 0; margin: 0 auto; @@ -41,5 +42,10 @@ justify-content: flex-start; align-items: center; pointer-events: none; + gap: 10px; + } + .notifications :global(.spectrum-Toast) { + width: 400px; + max-width: 100vw; } diff --git a/packages/client/src/stores/notification.js b/packages/client/src/stores/notification.js index e12eccf210..9c3dfd1523 100644 --- a/packages/client/src/stores/notification.js +++ b/packages/client/src/stores/notification.js @@ -1,18 +1,12 @@ import { writable, get } from "svelte/store" -import { generate } from "shortid" import { routeStore } from "./routes" const NOTIFICATION_TIMEOUT = 3000 const createNotificationStore = () => { - let timeout let block = false - const store = writable(null, () => { - return () => { - clearTimeout(timeout) - } - }) + const store = writable([]) const blockNotifications = (timeout = 1000) => { block = true @@ -37,26 +31,31 @@ const createNotificationStore = () => { }) return } - - store.set({ - id: generate(), - type, - message, - icon, - dismissable: !autoDismiss, - delay: get(store) != null, + const _id = id() + store.update(state => { + return [ + ...state, + { + id: _id, + type, + message, + icon, + dismissable: !autoDismiss, + delay: get(store) != null, + }, + ] }) - clearTimeout(timeout) if (autoDismiss) { - timeout = setTimeout(() => { - store.set(null) + setTimeout(() => { + dismiss(_id) }, NOTIFICATION_TIMEOUT) } } - const dismiss = () => { - clearTimeout(timeout) - store.set(null) + const dismiss = id => { + store.update(state => { + return state.filter(n => n.id !== id) + }) } return { @@ -71,6 +70,10 @@ const createNotificationStore = () => { dismiss, }, } + + function id() { + return "_" + Math.random().toString(36).slice(2, 9) + } } export const notificationStore = createNotificationStore() diff --git a/packages/client/src/utils/blocks.js b/packages/client/src/utils/blocks.js new file mode 100644 index 0000000000..3b97544238 --- /dev/null +++ b/packages/client/src/utils/blocks.js @@ -0,0 +1,81 @@ +import { makePropSafe as safe } from "@budibase/string-templates" + +// Map of data types to component types for search fields inside blocks +const schemaComponentMap = { + string: "stringfield", + options: "optionsfield", + number: "numberfield", + datetime: "datetimefield", + boolean: "booleanfield", + formula: "stringfield", +} + +/** + * Determine data types for search fields and only use those that are valid + * @param searchColumns the search columns to use + * @param schema the data source schema + */ +export const enrichSearchColumns = (searchColumns, schema) => { + let enrichedColumns = [] + searchColumns?.forEach(column => { + const schemaType = schema?.[column]?.type + const componentType = schemaComponentMap[schemaType] + if (componentType) { + enrichedColumns.push({ + name: column, + componentType, + type: schemaType, + }) + } + }) + return enrichedColumns.slice(0, 5) +} + +/** + * Enriches a normal datasource filter with bindings representing the additional + * search fields configured as part of a searchable block. These bindings are + * fields inside a form used as part of the block. + * @param filter the normal data provider filter + * @param columns the enriched search column structure + * @param formId the ID of the form containing the search fields + */ +export const enrichFilter = (filter, columns, formId) => { + let enrichedFilter = [...(filter || [])] + columns?.forEach(column => { + const safePath = column.name.split(".").map(safe).join(".") + const stringType = column.type === "string" || column.type === "formula" + const dateType = column.type === "datetime" + const binding = `${safe(formId)}.${safePath}` + + // For dates, use a range of the entire day selected + if (dateType) { + enrichedFilter.push({ + field: column.name, + type: column.type, + operator: "rangeLow", + valueType: "Binding", + value: `{{ ${binding} }}`, + }) + const format = "YYYY-MM-DDTHH:mm:ss.SSSZ" + enrichedFilter.push({ + field: column.name, + type: column.type, + operator: "rangeHigh", + valueType: "Binding", + value: `{{ date (add (date ${binding} "x") 86399999) "${format}" }}`, + }) + } + + // For other fields, do an exact match + else { + enrichedFilter.push({ + field: column.name, + type: column.type, + operator: stringType ? "string" : "equal", + valueType: "Binding", + value: `{{ ${binding} }}`, + }) + } + }) + return enrichedFilter +} diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 319c0a5feb..c6f46d1c67 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -179,8 +179,7 @@ const validateFormHandler = async (action, context) => { return await executeActionHandler( context, action.parameters.componentId, - ActionTypes.ValidateForm, - action.parameters.onlyCurrentStep + ActionTypes.ValidateForm ) } diff --git a/packages/client/yarn.lock b/packages/client/yarn.lock index d8e00d515e..0864699225 100644 --- a/packages/client/yarn.lock +++ b/packages/client/yarn.lock @@ -23,6 +23,46 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@rollup/plugin-alias@^3.1.5": version "3.1.8" resolved "https://registry.yarnpkg.com/@rollup/plugin-alias/-/plugin-alias-3.1.8.tgz#645fd84659e08d3d1b059408fcdf69c1dd435a6b" @@ -149,6 +189,11 @@ dependencies: "@types/node" "*" +acorn@^8.5.0: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -1350,9 +1395,9 @@ source-map-js@^1.0.1, source-map-js@^1.0.2: integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== source-map-support@~0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -1362,7 +1407,7 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3, source-map@~0.7.2: +source-map@^0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== @@ -1446,10 +1491,10 @@ svelte-spa-router@^3.0.5: dependencies: regexparam "2.0.0" -svelte@^3.38.2: - version "3.46.4" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.46.4.tgz#0c46bc4a3e20a2617a1b7dc43a722f9d6c084a38" - integrity sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg== +svelte@^3.49.0: + version "3.49.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" + integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== svg.draggable.js@^2.2.2: version "2.2.2" @@ -1520,12 +1565,13 @@ svgo@^2.7.0: stable "^0.1.8" terser@^5.0.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" - integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== + version "5.14.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" + integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" source-map-support "~0.5.20" timsort@^0.3.0: @@ -1536,7 +1582,7 @@ timsort@^0.3.0: util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== wrap-ansi@^7.0.0: version "7.0.0" diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 104b84e47f..c1b2dd289e 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "^1.1.31", + "@budibase/bbui": "1.1.33-alpha.0", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/frontend-core/src/api/groups.js b/packages/frontend-core/src/api/groups.js new file mode 100644 index 0000000000..ce0c8e7729 --- /dev/null +++ b/packages/frontend-core/src/api/groups.js @@ -0,0 +1,40 @@ +export const buildGroupsEndpoints = API => ({ + /** + * Creates a user group. + * @param user the new group to create + */ + saveGroup: async group => { + return await API.post({ + url: "/api/global/groups", + body: group, + }) + }, + /** + * Gets all of the user groups + */ + getGroups: async () => { + return await API.get({ + url: "/api/global/groups", + }) + }, + + /** + * Gets a group by ID + */ + getGroup: async id => { + return await API.get({ + url: `/api/global/groups/${id}`, + }) + }, + + /** + * Deletes a user group + * @param id the id of the config to delete + * @param rev the revision of the config to delete + */ + deleteGroup: async ({ id, rev }) => { + return await API.delete({ + url: `/api/global/groups/${id}/${rev}`, + }) + }, +}) diff --git a/packages/frontend-core/src/api/index.js b/packages/frontend-core/src/api/index.js index fddbffde4a..1db3b0b2f8 100644 --- a/packages/frontend-core/src/api/index.js +++ b/packages/frontend-core/src/api/index.js @@ -23,6 +23,7 @@ import { buildUserEndpoints } from "./user" import { buildSelfEndpoints } from "./self" import { buildViewEndpoints } from "./views" import { buildLicensingEndpoints } from "./licensing" +import { buildGroupsEndpoints } from "./groups" const defaultAPIClientConfig = { /** @@ -241,5 +242,6 @@ export const createAPIClient = config => { ...buildViewEndpoints(API), ...buildSelfEndpoints(API), ...buildLicensingEndpoints(API), + ...buildGroupsEndpoints(API), } } diff --git a/packages/frontend-core/src/api/user.js b/packages/frontend-core/src/api/user.js index b86e02c75b..17223a80e6 100644 --- a/packages/frontend-core/src/api/user.js +++ b/packages/frontend-core/src/api/user.js @@ -13,13 +13,16 @@ export const buildUserEndpoints = API => ({ * @param {string} page The page to retrieve * @param {string} search The starts with string to search username/email by. */ - searchUsers: async ({ page, search } = {}) => { + searchUsers: async ({ page, email, appId } = {}) => { const opts = {} if (page) { opts.page = page } - if (search) { - opts.search = search + if (email) { + opts.email = email + } + if (appId) { + opts.appId = appId } return await API.post({ url: `/api/global/users/search`, @@ -80,6 +83,20 @@ export const buildUserEndpoints = API => ({ }) }, + /** + * Creates multiple users. + * @param users the array of user objects to create + */ + createUsers: async ({ users, groups }) => { + return await API.post({ + url: "/api/global/users/bulkCreate", + body: { + users, + groups, + }, + }) + }, + /** * Deletes a user from the curernt tenant. * @param userId the ID of the user to delete @@ -90,6 +107,19 @@ export const buildUserEndpoints = API => ({ }) }, + /** + * Deletes multiple users + * @param userId the ID of the user to delete + */ + deleteUsers: async userIds => { + return await API.post({ + url: `/api/global/users/bulkDelete`, + body: { + userIds, + }, + }) + }, + /** * Invites a user to the current tenant. * @param email the email address to send the invitation to @@ -109,6 +139,25 @@ export const buildUserEndpoints = API => ({ }) }, + /** + * Invites multiple users to the current tenant. + * @param email An array of email addresses + * @param builder whether the user should be a global builder + * @param admin whether the user should be a global admin + */ + inviteUsers: async ({ emails, builder, admin }) => { + return await API.post({ + url: "/api/global/users/inviteMultiple", + body: { + emails, + userInfo: { + admin: admin ? { global: true } : undefined, + builder: builder ? { global: true } : undefined, + }, + }, + }) + }, + /** * Accepts an invite to join the platform and creates a user. * @param inviteCode the invite code sent in the email @@ -123,4 +172,15 @@ export const buildUserEndpoints = API => ({ }, }) }, + + /** + * Accepts an invite to join the platform and creates a user. + * @param inviteCode the invite code sent in the email + * @param password the password for the newly created user + */ + getUserCountByApp: async ({ appId }) => { + return await API.get({ + url: `/api/global/users/count/${appId}`, + }) + }, }) diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js index 74ce6ae881..77765f8d6e 100644 --- a/packages/frontend-core/src/constants.js +++ b/packages/frontend-core/src/constants.js @@ -35,7 +35,7 @@ export const OperatorOptions = { label: "Less than", }, Contains: { - value: "equal", + value: "contains", label: "Contains", }, NotContains: { @@ -60,6 +60,37 @@ export const TableNames = { USERS: "ta_users", } +export const BbRoles = [ + { label: "App User", value: "appUser" }, + { label: "Developer", value: "developer" }, + { label: "Admin", value: "admin" }, +] + +export const BuilderRoleDescriptions = [ + { + value: "appUser", + icon: "User", + label: "App user - Only has access to published apps", + }, + { + value: "developer", + icon: "Hammer", + label: "Developer - Access to the app builder", + }, + { + value: "admin", + icon: "Draw", + label: "Admin - Full access", + }, +] + +export const PlanType = { + FREE: "free", + TEAM: "team", + BUSINESS: "business", + ENTERPRISE: "enterprise", +} + /** * API version header attached to all requests. * Version changelog: @@ -68,6 +99,10 @@ export const TableNames = { */ export const ApiVersion = "1" +export const Features = { + USER_GROUPS: "userGroups", +} + // Role IDs export const Roles = { ADMIN: "ADMIN", @@ -76,7 +111,6 @@ export const Roles = { PUBLIC: "PUBLIC", BUILDER: "BUILDER", } - /** * Maximum minimum range for SQL number values */ diff --git a/packages/frontend-core/src/utils/lucene.js b/packages/frontend-core/src/utils/lucene.js index 29c2ca684a..b6699628d1 100644 --- a/packages/frontend-core/src/utils/lucene.js +++ b/packages/frontend-core/src/utils/lucene.js @@ -103,8 +103,16 @@ export const buildLuceneQuery = filter => { const isHbs = typeof value === "string" && value.match(HBS_REGEX)?.length > 0 // Parse all values into correct types - if (type === "datetime" && value) { - value = new Date(value).toISOString() + if (type === "datetime") { + // Ensure date value is a valid date and parse into correct format + if (!value) { + return + } + try { + value = new Date(value).toISOString() + } catch (error) { + return + } } if (type === "number" && !Array.isArray(value)) { if (operator === "oneOf") { diff --git a/packages/frontend-core/yarn.lock b/packages/frontend-core/yarn.lock index 8d4b2f14a0..7a2e6b7ba4 100644 --- a/packages/frontend-core/yarn.lock +++ b/packages/frontend-core/yarn.lock @@ -8,6 +8,6 @@ lodash@^4.17.21: integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== svelte@^3.46.2: - version "3.46.2" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.46.2.tgz#f0ffbffaea3a9a760edcbefc0902b41998a686ad" - integrity sha512-RXSAtYNefe01Sb1lXtZ2I+gzn3t/h/59hoaRNeRrm8IkMIu6BSiAkbpi41xb+C44x54YKnbk9+dtfs3pM4hECA== + version "3.49.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" + integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== diff --git a/packages/server/package.json b/packages/server/package.json index 3df8264388..8e7b737fae 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "description": "Budibase Web Server", "main": "src/index.ts", "repository": { @@ -77,11 +77,11 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "10.0.3", - "@budibase/backend-core": "^1.1.31", - "@budibase/client": "^1.1.31", - "@budibase/pro": "1.1.31", - "@budibase/string-templates": "^1.1.31", - "@budibase/types": "^1.1.31", + "@budibase/backend-core": "1.1.33-alpha.0", + "@budibase/client": "1.1.33-alpha.0", + "@budibase/pro": "1.1.33-alpha.0", + "@budibase/string-templates": "1.1.33-alpha.0", + "@budibase/types": "1.1.33-alpha.0", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", @@ -118,7 +118,7 @@ "koa-send": "5.0.0", "koa-session": "5.12.0", "koa-static": "5.0.0", - "koa2-ratelimit": "1.1.0", + "koa2-ratelimit": "1.1.1", "lodash": "4.17.21", "memorystream": "0.3.1", "mongodb": "3.6.3", @@ -137,7 +137,7 @@ "redis": "4", "server-destroy": "1.0.1", "snowflake-promise": "^4.5.0", - "svelte": "3.44.1", + "svelte": "3.49.0", "swagger-parser": "10.0.3", "to-json-schema": "0.2.5", "uuid": "3.3.2", diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index 7c1a093398..e2b66fc936 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -5,7 +5,11 @@ import { getDevelopmentAppID, } from "@budibase/backend-core/db" import { DocumentTypes, getAutomationParams } from "../../../db/utils" -import { disableAllCrons, enableCronTrigger } from "../../../automations/utils" +import { + disableAllCrons, + enableCronTrigger, + clearMetadata, +} from "../../../automations/utils" import { app as appCache } from "@budibase/backend-core/cache" import { getAppId, @@ -80,6 +84,7 @@ async function initDeployedApp(prodAppId: any) { }) ) ).rows.map((row: any) => row.doc) + await clearMetadata() console.log("You have " + automations.length + " automations") const promises = [] console.log("Disabling prod crons..") diff --git a/packages/server/src/api/controllers/query/index.ts b/packages/server/src/api/controllers/query/index.ts index 412bda62d3..187f16a573 100644 --- a/packages/server/src/api/controllers/query/index.ts +++ b/packages/server/src/api/controllers/query/index.ts @@ -246,7 +246,7 @@ async function execute( } export async function executeV1(ctx: any) { - return execute(ctx, { rowsOnly: true }) + return execute(ctx, { rowsOnly: true, isAutomation: false }) } export async function executeV2( diff --git a/packages/server/src/api/controllers/query/validation.js b/packages/server/src/api/controllers/query/validation.js index 2b5a3b310d..1279ebbe48 100644 --- a/packages/server/src/api/controllers/query/validation.js +++ b/packages/server/src/api/controllers/query/validation.js @@ -1,4 +1,4 @@ -const joiValidator = require("../../../middleware/joi-validator") +const { joiValidator } = require("@budibase/backend-core/auth") const Joi = require("joi") const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("") @@ -22,7 +22,7 @@ exports.queryValidation = () => { schema: Joi.object({}).required().unknown(true), transformer: OPTIONAL_STRING, flags: Joi.object().optional(), - }) + }).unknown(true) } exports.generateQueryValidation = () => { @@ -46,5 +46,5 @@ exports.generateQueryPreviewValidation = () => { transformer: OPTIONAL_STRING, parameters: Joi.object({}).required().unknown(true), queryId: OPTIONAL_STRING, - })) + }).unknown(true)) } diff --git a/packages/server/src/api/controllers/row/internalSearch.js b/packages/server/src/api/controllers/row/internalSearch.js index e6090ad8f0..8a04fc2bd0 100644 --- a/packages/server/src/api/controllers/row/internalSearch.js +++ b/packages/server/src/api/controllers/row/internalSearch.js @@ -19,6 +19,7 @@ class QueryBuilder { empty: {}, notEmpty: {}, oneOf: {}, + contains: {}, ...base, } this.limit = 50 @@ -119,6 +120,11 @@ class QueryBuilder { return this } + addContains(key, value) { + this.query.contains[key] = value + return this + } + /** * Preprocesses a value before going into a lucene search. * Transforms strings to lowercase and wraps strings and bools in quotes. @@ -164,6 +170,31 @@ class QueryBuilder { return `${key}:${builder.preprocess(value, allPreProcessingOpts)}` } + const contains = (key, value) => { + if (!value && value !== 0) { + return null + } + return `${key}:${builder.preprocess(value, { escape: true })}` + } + + const oneOf = (key, value) => { + if (!Array.isArray(value)) { + if (typeof value === "string") { + value = value.split(",") + } else { + return "" + } + } + let orStatement = `${builder.preprocess(value[0], allPreProcessingOpts)}` + for (let i = 1; i < value.length; i++) { + orStatement += ` OR ${builder.preprocess( + value[i], + allPreProcessingOpts + )}` + } + return `${key}:(${orStatement})` + } + function build(structure, queryFn) { for (let [key, value] of Object.entries(structure)) { key = builder.preprocess(key.replace(/ /g, "_"), { @@ -239,26 +270,10 @@ class QueryBuilder { build(this.query.notEmpty, key => `${key}:["" TO *]`) } if (this.query.oneOf) { - build(this.query.oneOf, (key, value) => { - if (!Array.isArray(value)) { - if (typeof value === "string") { - value = value.split(",") - } else { - return "" - } - } - let orStatement = `${builder.preprocess( - value[0], - allPreProcessingOpts - )}` - for (let i = 1; i < value.length; i++) { - orStatement += ` OR ${builder.preprocess( - value[i], - allPreProcessingOpts - )}` - } - return `${key}:(${orStatement})` - }) + build(this.query.oneOf, oneOf) + } + if (this.query.contains) { + build(this.query.contains, contains) } // make sure table ID is always added as an AND if (tableId) { diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js index 29c33b3899..e699f818d6 100644 --- a/packages/server/src/api/routes/tests/user.spec.js +++ b/packages/server/src/api/routes/tests/user.spec.js @@ -23,6 +23,7 @@ describe("/users", () => { }) describe("fetch", () => { + it("returns a list of users from an instance db", async () => { await config.createUser("uuidx") await config.createUser("uuidy") @@ -37,6 +38,7 @@ describe("/users", () => { expect(res.body.find(u => u._id === `ro_ta_users_us_uuidy`)).toBeDefined() }) + it("should apply authorization to endpoint", async () => { await config.createUser() await checkPermissionsEndpoint({ diff --git a/packages/server/src/api/routes/utils/validators.js b/packages/server/src/api/routes/utils/validators.js index 1a094e380b..b43eea9e36 100644 --- a/packages/server/src/api/routes/utils/validators.js +++ b/packages/server/src/api/routes/utils/validators.js @@ -1,4 +1,4 @@ -const joiValidator = require("../../../middleware/joi-validator") +const { joiValidator } = require("@budibase/backend-core/auth") const { DataSourceOperation } = require("../../../constants") const { WebhookType } = require("../../../constants") const { diff --git a/packages/server/src/automations/steps/executeQuery.js b/packages/server/src/automations/steps/executeQuery.js index 30f74e17be..93cc8e0fb8 100644 --- a/packages/server/src/automations/steps/executeQuery.js +++ b/packages/server/src/automations/steps/executeQuery.js @@ -74,6 +74,7 @@ exports.run = async function ({ inputs, appId, emitter }) { try { await queryController.executeV2(ctx, { isAutomation: true }) const { data, ...rest } = ctx.body + return { response: data, info: rest, diff --git a/packages/server/src/automations/tests/automation.spec.js b/packages/server/src/automations/tests/automation.spec.js index e7496fa4b3..168819daa3 100644 --- a/packages/server/src/automations/tests/automation.spec.js +++ b/packages/server/src/automations/tests/automation.spec.js @@ -31,7 +31,7 @@ describe("Run through some parts of the automations system", () => { it("should be able to init in builder", async () => { await triggers.externalTrigger(basicAutomation(), { a: 1 }) await wait(100) - expect(thread).toHaveBeenCalled() + expect(thread.execute).toHaveBeenCalled() }) it("should be able to init in prod", async () => { @@ -52,7 +52,7 @@ describe("Run through some parts of the automations system", () => { } }) await wait(100) - expect(thread).toHaveBeenCalledWith(makePartial({ + expect(thread.execute).toHaveBeenCalledWith(makePartial({ data: { event: { fields: { diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts index 906923b2e9..1799b4d74d 100644 --- a/packages/server/src/automations/utils.ts +++ b/packages/server/src/automations/utils.ts @@ -6,10 +6,16 @@ import newid from "../db/newid" import { updateEntityMetadata } from "../utilities" import { MetadataTypes, WebhookType } from "../constants" import { getProdAppID, doWithDB } from "@budibase/backend-core/db" +import { getAutomationMetadataParams } from "../db/utils" import { cloneDeep } from "lodash/fp" -import { getAppDB, getAppId } from "@budibase/backend-core/context" +import { + getAppDB, + getAppId, + getProdAppDB, +} from "@budibase/backend-core/context" import { tenancy } from "@budibase/backend-core" import { quotas } from "@budibase/pro" +import { Automation } from "@budibase/types" const WH_STEP_ID = definitions.WEBHOOK.stepId const CRON_STEP_ID = definitions.CRON.stepId @@ -82,6 +88,26 @@ export async function disableAllCrons(appId: any) { return Promise.all(promises) } +export async function disableCron(jobId: string, jobKey: string) { + await queue.removeRepeatableByKey(jobKey) + await queue.removeJobs(jobId) +} + +export async function clearMetadata() { + const db = getProdAppDB() + const automationMetadata = ( + await db.allDocs( + getAutomationMetadataParams({ + include_docs: true, + }) + ) + ).rows.map((row: any) => row.doc) + for (let metadata of automationMetadata) { + metadata._deleted = true + } + await db.bulkDocs(automationMetadata) +} + /** * This function handles checking of any cron jobs that need to be enabled/updated. * @param {string} appId The ID of the app in which we are checking for webhooks @@ -204,3 +230,30 @@ export async function checkForWebhooks({ oldAuto, newAuto }: any) { export async function cleanupAutomations(appId: any) { await disableAllCrons(appId) } + +/** + * Checks if the supplied automation is of a recurring type. + * @param automation The automation to check. + * @return {boolean} if it is recurring (cron). + */ +export function isRecurring(automation: Automation) { + return automation.definition.trigger.stepId === definitions.CRON.stepId +} + +export function isErrorInOutput(output: { + steps: { outputs?: { success: boolean } }[] +}) { + let first = true, + error = false + for (let step of output.steps) { + // skip the trigger, its always successful if automation ran + if (first) { + first = false + continue + } + if (!step.outputs?.success) { + error = true + } + } + return error +} diff --git a/packages/server/src/constants/index.js b/packages/server/src/constants/index.js index 3aa5b2fb7b..c002c10f7b 100644 --- a/packages/server/src/constants/index.js +++ b/packages/server/src/constants/index.js @@ -208,10 +208,7 @@ exports.AutomationErrors = { FAILURE_CONDITION: "FAILURE_CONDITION_MET", } -exports.LoopStepTypes = { - ARRAY: "Array", - STRING: "String", -} - // pass through the list from the auth/core lib exports.ObjectStoreBuckets = ObjectStoreBuckets + +exports.MAX_AUTOMATION_RECURRING_ERRORS = 5 diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 152b0e9d33..8372040723 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -41,6 +41,7 @@ const DocumentTypes = { METADATA: "metadata", MEM_VIEW: "view", USER_FLAG: "flag", + AUTOMATION_METADATA: "meta_au", } const InternalTables = { @@ -311,6 +312,21 @@ exports.generateQueryID = datasourceId => { }${SEPARATOR}${datasourceId}${SEPARATOR}${newid()}` } +/** + * Generates a metadata ID for automations, used to track errors in recurring + * automations etc. + */ +exports.generateAutomationMetadataID = automationId => { + return `${DocumentTypes.AUTOMATION_METADATA}${SEPARATOR}${automationId}` +} + +/** + * Retrieve all automation metadata in an app database. + */ +exports.getAutomationMetadataParams = (otherProps = {}) => { + return getDocParams(DocumentTypes.AUTOMATION_METADATA, null, otherProps) +} + /** * Gets parameters for retrieving a query, this is a utility function for the getDocParams function. */ diff --git a/packages/server/src/definitions/automations.ts b/packages/server/src/definitions/automations.ts new file mode 100644 index 0000000000..e1ac690bf1 --- /dev/null +++ b/packages/server/src/definitions/automations.ts @@ -0,0 +1,49 @@ +import { + Automation, + AutomationResults, + AutomationStep, + Document, +} from "@budibase/types" + +export enum LoopStepTypes { + ARRAY = "Array", + STRING = "String", +} + +export interface LoopStep extends AutomationStep { + inputs: { + option: LoopStepTypes + [key: string]: any + } +} + +export interface LoopInput { + binding: string[] | string +} + +export interface TriggerOutput { + metadata?: any + appId?: string + timestamp?: number +} + +export interface AutomationEvent { + data: { + automation: Automation + event: any + } + opts?: { + repeat?: { + jobId: string + } + } +} + +export interface AutomationContext extends AutomationResults { + steps: any[] + trigger: any +} + +export interface AutomationMetadata extends Document { + errorCount?: number +} diff --git a/packages/server/src/definitions/datasource.ts b/packages/server/src/definitions/datasource.ts index 90c81abe9f..9752fc947a 100644 --- a/packages/server/src/definitions/datasource.ts +++ b/packages/server/src/definitions/datasource.ts @@ -131,6 +131,9 @@ export interface SearchFilters { oneOf?: { [key: string]: any[] } + contains?: { + [key: string]: any + } } export interface SortJson { diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index fbbc42151a..750564c6ff 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -142,6 +142,21 @@ class InternalBuilder { } } } + + const like = (key: string, value: any) => { + const fnc = allOr ? "orWhere" : "where" + // postgres supports ilike, nothing else does + if (this.client === SqlClients.POSTGRES) { + query = query[fnc](key, "ilike", `%${value}%`) + } else { + const rawFnc = `${fnc}Raw` + // @ts-ignore + query = query[rawFnc](`LOWER(${likeKey(this.client, key)}) LIKE ?`, [ + `%${value}%`, + ]) + } + } + if (!filters) { return query } @@ -168,19 +183,7 @@ class InternalBuilder { }) } if (filters.fuzzy) { - iterate(filters.fuzzy, (key, value) => { - const fnc = allOr ? "orWhere" : "where" - // postgres supports ilike, nothing else does - if (this.client === SqlClients.POSTGRES) { - query = query[fnc](key, "ilike", `%${value}%`) - } else { - const rawFnc = `${fnc}Raw` - // @ts-ignore - query = query[rawFnc](`LOWER(${likeKey(this.client, key)}) LIKE ?`, [ - `%${value}%`, - ]) - } - }) + iterate(filters.fuzzy, like) } if (filters.range) { iterate(filters.range, (key, value) => { @@ -223,6 +226,34 @@ class InternalBuilder { query = query[fnc](key) }) } + if (filters.contains) { + const fnc = allOr ? "orWhere" : "where" + const rawFnc = `${fnc}Raw` + if (this.client === SqlClients.POSTGRES) { + iterate(filters.contains, (key: string, value: any) => { + const fieldNames = key.split(/\./g) + const tableName = fieldNames[0] + const columnName = fieldNames[1] + if (typeof value === "string") { + value = `"${value}"` + } + // @ts-ignore + query = query[rawFnc]( + `"${tableName}"."${columnName}"::jsonb @> '[${value}]'` + ) + }) + } else if (this.client === SqlClients.MY_SQL) { + iterate(filters.contains, (key: string, value: any) => { + if (typeof value === "string") { + value = `"${value}"` + } + // @ts-ignore + query = query[rawFnc](`JSON_CONTAINS(${key}, '${value}')`) + }) + } else { + iterate(filters.contains, like) + } + } return query } diff --git a/packages/server/src/integrations/tests/sql.spec.js b/packages/server/src/integrations/tests/sql.spec.js index c2e65c56b7..55c762573a 100644 --- a/packages/server/src/integrations/tests/sql.spec.js +++ b/packages/server/src/integrations/tests/sql.spec.js @@ -1,4 +1,5 @@ const Sql = require("../base/sql") +const { SqlClients } = require("../utils") const TABLE_NAME = "test" @@ -46,7 +47,7 @@ function generateDeleteJson(table = TABLE_NAME, filters = {}) { describe("SQL query builder", () => { const limit = 500 - const client = "pg" + const client = SqlClients.POSTGRES let sql beforeEach(() => { @@ -173,15 +174,15 @@ describe("SQL query builder", () => { }) it("should work with MS-SQL", () => { - const query = new Sql("mssql", 10)._query(generateReadJson()) + const query = new Sql(SqlClients.MS_SQL, 10)._query(generateReadJson()) expect(query).toEqual({ bindings: [10], sql: `select * from (select top (@p0) * from [${TABLE_NAME}]) as [${TABLE_NAME}]` }) }) - it("should work with mySQL", () => { - const query = new Sql("mysql", 10)._query(generateReadJson()) + it("should work with MySQL", () => { + const query = new Sql(SqlClients.MY_SQL, 10)._query(generateReadJson()) expect(query).toEqual({ bindings: [10], sql: `select * from (select * from \`${TABLE_NAME}\` limit ?) as \`${TABLE_NAME}\`` @@ -238,4 +239,49 @@ describe("SQL query builder", () => { sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" > $1 limit $2) as "${TABLE_NAME}"` }) }) + + it("should use like expression for MS-SQL when filter is contains", () => { + const query = new Sql(SqlClients.MS_SQL, 10)._query(generateReadJson({ + filters: { + contains: { + age: 20, + name: "John" + } + } + })) + expect(query).toEqual({ + bindings: [10, "%20%", "%John%"], + sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where LOWER(${TABLE_NAME}.age) LIKE @p1 and LOWER(${TABLE_NAME}.name) LIKE @p2) as [${TABLE_NAME}]` + }) + }) + + it("should use JSON_CONTAINS expression for MySQL when filter is contains", () => { + const query = new Sql(SqlClients.MY_SQL, 10)._query(generateReadJson({ + filters: { + contains: { + age: 20, + name: "John" + } + } + })) + expect(query).toEqual({ + bindings: [10], + sql: `select * from (select * from \`${TABLE_NAME}\` where JSON_CONTAINS(${TABLE_NAME}.age, '20') and JSON_CONTAINS(${TABLE_NAME}.name, '"John"') limit ?) as \`${TABLE_NAME}\`` + }) + }) + + it("should use jsonb operator expression for PostgreSQL when filter is contains", () => { + const query = new Sql(SqlClients.POSTGRES, 10)._query(generateReadJson({ + filters: { + contains: { + age: 20, + name: "John" + } + } + })) + expect(query).toEqual({ + bindings: [10], + sql: `select * from (select * from \"${TABLE_NAME}\" where \"${TABLE_NAME}\".\"age\"::jsonb @> '[20]' and \"${TABLE_NAME}\".\"name\"::jsonb @> '["John"]' limit $1) as \"${TABLE_NAME}\"` + }) + }) }) diff --git a/packages/server/src/middleware/tests/currentapp.spec.js b/packages/server/src/middleware/tests/currentapp.spec.js index 85447581cc..57c21b2107 100644 --- a/packages/server/src/middleware/tests/currentapp.spec.js +++ b/packages/server/src/middleware/tests/currentapp.spec.js @@ -1,5 +1,6 @@ mockAuthWithNoCookie() mockWorker() +mockUserGroups() jest.mock("@budibase/backend-core/db", () => { const coreDb = jest.requireActual("@budibase/backend-core/db") @@ -29,6 +30,16 @@ function mockReset() { mockWorker() } +function mockUserGroups() { + jest.mock("@budibase/pro", () => ({ + groups: { + getGroupRoleId: () => { + return "BASIC" + }, + }, + })) +} + function mockAuthWithNoCookie() { jest.resetModules() mockWorker() diff --git a/packages/server/src/threads/automation.js b/packages/server/src/threads/automation.ts similarity index 61% rename from packages/server/src/threads/automation.js rename to packages/server/src/threads/automation.ts index 8880f0cbcb..0b8d2e89bd 100644 --- a/packages/server/src/threads/automation.js +++ b/packages/server/src/threads/automation.ts @@ -1,36 +1,47 @@ -require("./utils").threadSetup() -const actions = require("../automations/actions") -const automationUtils = require("../automations/automationUtils") -const AutomationEmitter = require("../events/AutomationEmitter") -const { processObject } = require("@budibase/string-templates") -const { DocumentTypes } = require("../db/utils") -const { definitions: triggerDefs } = require("../automations/triggerInfo") +import { default as threadUtils } from "./utils" +threadUtils.threadSetup() +import { isRecurring, disableCron, isErrorInOutput } from "../automations/utils" +import { default as actions } from "../automations/actions" +import { default as automationUtils } from "../automations/automationUtils" +import { default as AutomationEmitter } from "../events/AutomationEmitter" +import { generateAutomationMetadataID, isProdAppID } from "../db/utils" +import { definitions as triggerDefs } from "../automations/triggerInfo" +import { AutomationErrors, MAX_AUTOMATION_RECURRING_ERRORS } from "../constants" +import { storeLog } from "../automations/logging" +import { Automation, AutomationStep, AutomationStatus } from "@budibase/types" +import { + LoopStep, + LoopStepTypes, + LoopInput, + AutomationEvent, + TriggerOutput, + AutomationContext, + AutomationMetadata, +} from "../definitions/automations" +import { WorkerCallback } from "./definitions" const { doInAppContext, getAppDB } = require("@budibase/backend-core/context") -const { AutomationErrors, LoopStepTypes } = require("../constants") -const { storeLog } = require("../automations/logging") +const { logAlertWithInfo, logWarn } = require("@budibase/backend-core/logging") +const { processObject } = require("@budibase/string-templates") const FILTER_STEP_ID = actions.ACTION_DEFINITIONS.FILTER.stepId const LOOP_STEP_ID = actions.ACTION_DEFINITIONS.LOOP.stepId - const CRON_STEP_ID = triggerDefs.CRON.stepId -const STOPPED_STATUS = { success: true, status: "STOPPED" } +const STOPPED_STATUS = { success: true, status: AutomationStatus.STOPPED } const { cloneDeep } = require("lodash/fp") const env = require("../environment") -function typecastForLooping(loopStep, input) { +function typecastForLooping(loopStep: LoopStep, input: LoopInput) { if (!input || !input.binding) { return null } - const isArray = Array.isArray(input.binding), - isString = typeof input.binding === "string" try { switch (loopStep.inputs.option) { case LoopStepTypes.ARRAY: - if (isString) { + if (typeof input.binding === "string") { return JSON.parse(input.binding) } break case LoopStepTypes.STRING: - if (isArray) { + if (Array.isArray(input.binding)) { return input.binding.join(",") } break @@ -41,7 +52,7 @@ function typecastForLooping(loopStep, input) { return input.binding } -function getLoopIterations(loopStep, input) { +function getLoopIterations(loopStep: LoopStep, input: LoopInput) { const binding = typecastForLooping(loopStep, input) if (!loopStep || !binding) { return 1 @@ -57,11 +68,24 @@ function getLoopIterations(loopStep, input) { * inputs and handles any outputs. */ class Orchestrator { - constructor(automation, triggerOutput = {}) { - this._metadata = triggerOutput.metadata - this._chainCount = this._metadata ? this._metadata.automationChainCount : 0 - this._appId = triggerOutput.appId - this._app = null + _chainCount: number + _appId: string + _automation: Automation + _emitter: any + _context: AutomationContext + _repeat?: { jobId: string; jobKey: string } + executionOutput: AutomationContext + + constructor(automation: Automation, triggerOutput: TriggerOutput, opts: any) { + const metadata = triggerOutput.metadata + this._chainCount = metadata ? metadata.automationChainCount : 0 + this._appId = triggerOutput.appId as string + if (opts?.repeat) { + this._repeat = { + jobId: opts.repeat.jobId, + jobKey: opts.repeat.key, + } + } const triggerStepId = automation.definition.trigger.stepId triggerOutput = this.cleanupTriggerOutputs(triggerStepId, triggerOutput) // remove from context @@ -79,14 +103,14 @@ class Orchestrator { this.updateExecutionOutput(triggerId, triggerStepId, null, triggerOutput) } - cleanupTriggerOutputs(stepId, triggerOutput) { + cleanupTriggerOutputs(stepId: string, triggerOutput: TriggerOutput) { if (stepId === CRON_STEP_ID) { triggerOutput.timestamp = Date.now() } return triggerOutput } - async getStepFunctionality(stepId) { + async getStepFunctionality(stepId: string) { let step = await actions.getAction(stepId) if (step == null) { throw `Cannot find automation step by name ${stepId}` @@ -94,25 +118,107 @@ class Orchestrator { return step } - async getApp() { - if (this._app) { - return this._app - } + async getMetadata(): Promise { + const metadataId = generateAutomationMetadataID(this._automation._id) const db = getAppDB() - this._app = await db.get(DocumentTypes.APP_METADATA) - return this._app + let metadata: AutomationMetadata + try { + metadata = await db.get(metadataId) + } catch (err) { + metadata = { + _id: metadataId, + errorCount: 0, + } + } + return metadata } - updateExecutionOutput(id, stepId, inputs, outputs) { + async checkIfShouldStop(metadata: AutomationMetadata): Promise { + if (!metadata.errorCount || !this._repeat) { + return false + } + const automation = this._automation + const trigger = automation.definition.trigger + if (metadata.errorCount >= MAX_AUTOMATION_RECURRING_ERRORS) { + logWarn( + `CRON disabled due to errors - ${this._appId}/${this._automation._id}` + ) + await disableCron(this._repeat?.jobId, this._repeat?.jobKey) + this.updateExecutionOutput( + trigger.id, + trigger.stepId, + {}, + { + status: AutomationStatus.STOPPED_ERROR, + success: false, + } + ) + await storeLog(automation, this.executionOutput) + return true + } + return false + } + + async updateMetadata(metadata: AutomationMetadata) { + const output = this.executionOutput, + automation = this._automation + if (!output || !isRecurring(automation)) { + return + } + const count = metadata.errorCount + const isError = isErrorInOutput(output) + // nothing to do in this scenario, escape + if (!count && !isError) { + return + } + if (isError) { + metadata.errorCount = count ? count + 1 : 1 + } else { + metadata.errorCount = 0 + } + const db = getAppDB() + try { + await db.put(metadata) + } catch (err) { + logAlertWithInfo( + "Failed to write automation metadata", + db.name, + automation._id, + err + ) + } + } + + updateExecutionOutput(id: string, stepId: string, inputs: any, outputs: any) { const stepObj = { id, stepId, inputs, outputs } + // replacing trigger when disabling CRON + if ( + stepId === CRON_STEP_ID && + outputs.status === AutomationStatus.STOPPED_ERROR + ) { + this.executionOutput.trigger = stepObj + this.executionOutput.steps = [stepObj] + return + } // first entry is always the trigger (constructor) - if (this.executionOutput.steps.length === 0) { + if ( + this.executionOutput.steps.length === 0 || + this.executionOutput.trigger.id === id + ) { this.executionOutput.trigger = stepObj } this.executionOutput.steps.push(stepObj) } - updateContextAndOutput(loopStepNumber, step, output, result) { + updateContextAndOutput( + loopStepNumber: number | undefined, + step: AutomationStep, + output: any, + result: { success: boolean; status: string } + ) { + if (!loopStepNumber) { + throw new Error("No loop step number provided.") + } this.executionOutput.steps.splice(loopStepNumber, 0, { id: step.id, stepId: step.stepId, @@ -133,11 +239,22 @@ class Orchestrator { async execute() { let automation = this._automation let stopped = false - let loopStep = null + let loopStep: AutomationStep | undefined = undefined let stepCount = 0 - let loopStepNumber = null - let loopSteps = [] + let loopStepNumber: any = undefined + let loopSteps: LoopStep[] | undefined = [] + let metadata + + // check if this is a recurring automation, + if (isProdAppID(this._appId) && isRecurring(automation)) { + metadata = await this.getMetadata() + const shouldStop = await this.checkIfShouldStop(metadata) + if (shouldStop) { + return + } + } + for (let step of automation.definition.steps) { stepCount++ let input, @@ -151,7 +268,7 @@ class Orchestrator { if (loopStep) { input = await processObject(loopStep.inputs, this._context) - iterations = getLoopIterations(loopStep, input) + iterations = getLoopIterations(loopStep as LoopStep, input) } for (let index = 0; index < iterations; index++) { @@ -166,14 +283,17 @@ class Orchestrator { let tempOutput = { items: loopSteps, iterations: iterationCount } try { - newInput.binding = typecastForLooping(loopStep, newInput) + newInput.binding = typecastForLooping( + loopStep as LoopStep, + newInput + ) } catch (err) { this.updateContextAndOutput(loopStepNumber, step, tempOutput, { status: AutomationErrors.INCORRECT_TYPE, success: false, }) - loopSteps = null - loopStep = null + loopSteps = undefined + loopStep = undefined break } @@ -223,8 +343,8 @@ class Orchestrator { status: AutomationErrors.MAX_ITERATIONS, success: true, }) - loopSteps = null - loopStep = null + loopSteps = undefined + loopStep = undefined break } @@ -232,7 +352,7 @@ class Orchestrator { const currentItem = this._context.steps[loopStepNumber]?.currentItem if (currentItem && typeof currentItem === "object") { isFailure = Object.keys(currentItem).some(value => { - return currentItem[value] === loopStep.inputs.failure + return currentItem[value] === loopStep?.inputs.failure }) } else { isFailure = currentItem && currentItem === loopStep.inputs.failure @@ -243,8 +363,8 @@ class Orchestrator { status: AutomationErrors.FAILURE_CONDITION, success: false, }) - loopSteps = null - loopStep = null + loopSteps = undefined + loopStep = undefined break } } @@ -295,7 +415,7 @@ class Orchestrator { if (loopStep) { iterationCount++ if (index === iterations - 1) { - loopStep = null + loopStep = undefined this._context.steps.splice(loopStepNumber, 1) break } @@ -316,22 +436,26 @@ class Orchestrator { }) this._context.steps.splice(loopStepNumber, 0, tempOutput) - loopSteps = null + loopSteps = undefined } } // store the logs for the automation run await storeLog(this._automation, this.executionOutput) + if (isProdAppID(this._appId) && isRecurring(automation) && metadata) { + await this.updateMetadata(metadata) + } return this.executionOutput } } -module.exports = (input, callback) => { +export function execute(input: AutomationEvent, callback: WorkerCallback) { const appId = input.data.event.appId doInAppContext(appId, async () => { const automationOrchestrator = new Orchestrator( input.data.automation, - input.data.event + input.data.event, + input.opts ) try { const response = await automationOrchestrator.execute() diff --git a/packages/server/src/threads/definitions.ts b/packages/server/src/threads/definitions.ts new file mode 100644 index 0000000000..3da69d3640 --- /dev/null +++ b/packages/server/src/threads/definitions.ts @@ -0,0 +1,18 @@ +export type WorkerCallback = (error: any, response?: any) => void + +export interface QueryEvent { + appId?: string + datasource: any + queryVerb: string + fields: { [key: string]: any } + parameters: { [key: string]: any } + pagination?: any + transformer: any + queryId: string + ctx?: any +} + +export interface QueryVariable { + queryId: string + name: string +} diff --git a/packages/server/src/threads/index.ts b/packages/server/src/threads/index.ts index b39224cbb5..f112fdca5e 100644 --- a/packages/server/src/threads/index.ts +++ b/packages/server/src/threads/index.ts @@ -18,26 +18,23 @@ function typeToFile(type: any) { default: throw "Unknown thread type" } + // have to use require here, to make it work with worker-farm return require.resolve(filename) } export class Thread { type: any count: any - disableThreading: any workers: any timeoutMs: any + disableThreading: boolean static workerRefs: any[] = [] constructor(type: any, opts: any = { timeoutMs: null, count: 1 }) { this.type = type this.count = opts.count ? opts.count : 1 - this.disableThreading = - env.isTest() || - env.DISABLE_THREADING || - this.count === 0 || - env.isInThread() + this.disableThreading = this.shouldDisableThreading() if (!this.disableThreading) { const workerOpts: any = { autoStart: true, @@ -47,33 +44,44 @@ export class Thread { this.timeoutMs = opts.timeoutMs workerOpts.maxCallTime = opts.timeoutMs } - this.workers = workerFarm(workerOpts, typeToFile(type)) + this.workers = workerFarm(workerOpts, typeToFile(type), ["execute"]) Thread.workerRefs.push(this.workers) } } + shouldDisableThreading(): boolean { + return !!( + env.isTest() || + env.DISABLE_THREADING || + this.count === 0 || + env.isInThread() + ) + } + run(data: any) { + const timeout = this.timeoutMs return new Promise((resolve, reject) => { - let fncToCall + function fire(worker: any) { + worker.execute(data, (err: any, response: any) => { + if (err && err.type === "TimeoutError") { + reject( + new Error(`Query response time exceeded ${timeout}ms timeout.`) + ) + } else if (err) { + reject(err) + } else { + resolve(response) + } + }) + } // if in test then don't use threading if (this.disableThreading) { - fncToCall = require(typeToFile(this.type)) + import(typeToFile(this.type)).then((thread: any) => { + fire(thread) + }) } else { - fncToCall = this.workers + fire(this.workers) } - fncToCall(data, (err: any, response: any) => { - if (err && err.type === "TimeoutError") { - reject( - new Error( - `Query response time exceeded ${this.timeoutMs}ms timeout.` - ) - ) - } else if (err) { - reject(err) - } else { - resolve(response) - } - }) }) } diff --git a/packages/server/src/threads/query.js b/packages/server/src/threads/query.ts similarity index 87% rename from packages/server/src/threads/query.js rename to packages/server/src/threads/query.ts index 757fdc040b..6b93a00200 100644 --- a/packages/server/src/threads/query.js +++ b/packages/server/src/threads/query.ts @@ -1,5 +1,6 @@ -const threadUtils = require("./utils") +import { default as threadUtils } from "./utils" threadUtils.threadSetup() +import { WorkerCallback, QueryEvent, QueryVariable } from "./definitions" const ScriptRunner = require("../utilities/scriptRunner") const { integrations } = require("../integrations") const { processStringSync } = require("@budibase/string-templates") @@ -19,7 +20,22 @@ const { } = require("../integrations/queries/sql") class QueryRunner { - constructor(input, flags = { noRecursiveQuery: false }) { + datasource: any + queryVerb: string + queryId: string + fields: any + parameters: any + pagination: any + transformer: any + cachedVariables: any[] + ctx: any + queryResponse: any + noRecursiveQuery: boolean + hasRerun: boolean + hasRefreshedOAuth: boolean + hasDynamicVariables: boolean + + constructor(input: QueryEvent, flags = { noRecursiveQuery: false }) { this.datasource = input.datasource this.queryVerb = input.queryVerb this.fields = input.fields @@ -37,9 +53,10 @@ class QueryRunner { this.queryResponse = {} this.hasRerun = false this.hasRefreshedOAuth = false + this.hasDynamicVariables = false } - async execute() { + async execute(): Promise { let { datasource, fields, queryVerb, transformer } = this let datasourceClone = cloneDeep(datasource) @@ -52,7 +69,7 @@ class QueryRunner { if (datasourceClone.config.authConfigs) { datasourceClone.config.authConfigs = - datasourceClone.config.authConfigs.map(config => { + datasourceClone.config.authConfigs.map((config: any) => { return enrichQueryFields(config, this.ctx) }) } @@ -138,8 +155,8 @@ class QueryRunner { } // map into JSON if just raw primitive here - if (rows.find(row => typeof row !== "object")) { - rows = rows.map(value => ({ value })) + if (rows.find((row: any) => typeof row !== "object")) { + rows = rows.map((value: any) => ({ value })) } // get all the potential fields in the schema @@ -152,7 +169,7 @@ class QueryRunner { return { rows, keys, info, extra, pagination } } - async runAnotherQuery(queryId, parameters) { + async runAnotherQuery(queryId: string, parameters: any) { const db = getAppDB() const query = await db.get(queryId) const datasource = await db.get(query.datasourceId) @@ -163,12 +180,13 @@ class QueryRunner { fields: query.fields, parameters, transformer: query.transformer, + queryId, }, { noRecursiveQuery: true } ).execute() } - async refreshOAuth2(ctx) { + async refreshOAuth2(ctx: any) { const { oauth2, providerType, _id } = ctx.user const { configId } = ctx.auth @@ -200,7 +218,7 @@ class QueryRunner { return resp } - async getDynamicVariable(variable) { + async getDynamicVariable(variable: QueryVariable) { let { parameters } = this const queryId = variable.queryId, name = variable.name @@ -233,7 +251,7 @@ class QueryRunner { if (!this.noRecursiveQuery) { // need to see if this uses any variables const stringFields = JSON.stringify(fields) - const foundVars = dynamicVars.filter(variable => { + const foundVars = dynamicVars.filter((variable: QueryVariable) => { // don't allow a query to use its own dynamic variable (loop) if (variable.queryId === this.queryId) { return false @@ -242,7 +260,9 @@ class QueryRunner { const regex = new RegExp(`{{[ ]*${variable.name}[ ]*}}`) return regex.test(stringFields) }) - const dynamics = foundVars.map(dynVar => this.getDynamicVariable(dynVar)) + const dynamics = foundVars.map((dynVar: QueryVariable) => + this.getDynamicVariable(dynVar) + ) const responses = await Promise.all(dynamics) for (let i = 0; i < foundVars.length; i++) { const variable = foundVars[i] @@ -264,7 +284,7 @@ class QueryRunner { } } -module.exports = (input, callback) => { +export function execute(input: QueryEvent, callback: WorkerCallback) { doInAppContext(input.appId, async () => { const Runner = new QueryRunner(input) try { diff --git a/packages/server/src/threads/utils.js b/packages/server/src/threads/utils.ts similarity index 65% rename from packages/server/src/threads/utils.js rename to packages/server/src/threads/utils.ts index 77824eba96..a51c861b00 100644 --- a/packages/server/src/threads/utils.js +++ b/packages/server/src/threads/utils.ts @@ -1,10 +1,11 @@ +import { QueryVariable } from "./definitions" const env = require("../environment") const db = require("../db") const redis = require("@budibase/backend-core/redis") const { SEPARATOR } = require("@budibase/backend-core/db") const VARIABLE_TTL_SECONDS = 3600 -let client +let client: any async function getClient() { if (!client) { @@ -14,10 +15,16 @@ async function getClient() { } process.on("exit", async () => { - if (client) await client.finish() + if (client) { + await client.finish() + } }) -exports.threadSetup = () => { +function makeVariableKey(queryId: string, variable: string) { + return `${queryId}${SEPARATOR}${variable}` +} + +export function threadSetup() { // don't run this if not threading if (env.isTest() || env.DISABLE_THREADING) { return @@ -27,16 +34,15 @@ exports.threadSetup = () => { db.init() } -function makeVariableKey(queryId, variable) { - return `${queryId}${SEPARATOR}${variable}` -} - -exports.checkCacheForDynamicVariable = async (queryId, variable) => { +export async function checkCacheForDynamicVariable( + queryId: string, + variable: string +) { const cache = await getClient() return cache.get(makeVariableKey(queryId, variable)) } -exports.invalidateDynamicVariables = async cachedVars => { +export async function invalidateDynamicVariables(cachedVars: QueryVariable[]) { const cache = await getClient() let promises = [] for (let variable of cachedVars) { @@ -47,7 +53,11 @@ exports.invalidateDynamicVariables = async cachedVars => { await Promise.all(promises) } -exports.storeDynamicVariable = async (queryId, variable, value) => { +export async function storeDynamicVariable( + queryId: string, + variable: string, + value: any +) { const cache = await getClient() await cache.store( makeVariableKey(queryId, variable), @@ -56,7 +66,7 @@ exports.storeDynamicVariable = async (queryId, variable, value) => { ) } -exports.formatResponse = resp => { +export function formatResponse(resp: any) { if (typeof resp === "string") { try { resp = JSON.parse(resp) @@ -67,7 +77,7 @@ exports.formatResponse = resp => { return resp } -exports.hasExtraData = response => { +export function hasExtraData(response: any) { return ( typeof response === "object" && !Array.isArray(response) && @@ -76,3 +86,12 @@ exports.hasExtraData = response => { response.info != null ) } + +export default { + hasExtraData, + formatResponse, + storeDynamicVariable, + invalidateDynamicVariables, + checkCacheForDynamicVariable, + threadSetup, +} diff --git a/packages/server/src/utilities/global.js b/packages/server/src/utilities/global.js index f8ec5ea647..462ef6ba5d 100644 --- a/packages/server/src/utilities/global.js +++ b/packages/server/src/utilities/global.js @@ -12,9 +12,11 @@ const { } = require("@budibase/backend-core/tenancy") const env = require("../environment") const { getAppId } = require("@budibase/backend-core/context") +const { groups } = require("@budibase/pro") exports.updateAppRole = (user, { appId } = {}) => { appId = appId || getAppId() + if (!user || !user.roles) { return user } @@ -30,18 +32,33 @@ exports.updateAppRole = (user, { appId } = {}) => { // if a role wasn't found then either set as admin (builder) or public (everyone else) if (!user.roleId && user.builder && user.builder.global) { user.roleId = BUILTIN_ROLE_IDS.ADMIN - } else if (!user.roleId) { + } else if (!user.roleId && !user?.userGroups?.length) { user.roleId = BUILTIN_ROLE_IDS.PUBLIC + } else if (user?.userGroups?.length) { + user.roleId = null } + delete user.roles return user } -function processUser(user, { appId } = {}) { +async function checkGroupRoles(user, { appId } = {}) { + let roleId = await groups.getGroupRoleId(user, appId) + user.roleId = roleId + + return user +} + +async function processUser(user, { appId } = {}) { if (user) { delete user.password } - return exports.updateAppRole(user, { appId }) + user = await exports.updateAppRole(user, { appId }) + if (!user.roleId && user?.userGroups?.length) { + user = await checkGroupRoles(user, { appId }) + } + + return user } exports.getCachedSelf = async (ctx, appId) => { @@ -89,6 +106,7 @@ exports.getGlobalUsers = async (users = null) => { if (!appId) { return globalUsers } + return globalUsers.map(user => exports.updateAppRole(user)) } diff --git a/packages/server/src/utilities/queue/inMemoryQueue.js b/packages/server/src/utilities/queue/inMemoryQueue.js index 375092609e..620b65cf38 100644 --- a/packages/server/src/utilities/queue/inMemoryQueue.js +++ b/packages/server/src/utilities/queue/inMemoryQueue.js @@ -109,6 +109,10 @@ class InMemoryQueue { async clean() { return [] } + + async getJob() { + return {} + } } module.exports = InMemoryQueue diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index f8ad9f58e1..78abada5a9 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1094,12 +1094,12 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.1.31.tgz#914283af0928ced36303ad4919e52314a8f68022" - integrity sha512-Uo2CxX87u8Lq5MyYOVAXw/wmawUAAUnWkJ648RR1v8CikjOpOixjIiIwb8fXOr1No2SwD4HjY/V/xZGXCgxilQ== +"@budibase/backend-core@1.1.33-alpha.0": + version "1.1.33-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.1.33-alpha.0.tgz#8a502a038c3a86fa061bc53c9538deed0598b96c" + integrity sha512-QSUX8sOHMip2XYbjAehhcFHpHucCOAQOR8sW20WDjofR/+DEHRuvkHXetgJvcl0CMPey8dmh98H+yeQio1kYcQ== dependencies: - "@budibase/types" "^1.1.31" + "@budibase/types" "1.1.33-alpha.0" "@techpass/passport-openidconnect" "0.3.2" aws-sdk "2.1030.0" bcrypt "5.0.1" @@ -1177,13 +1177,15 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" -"@budibase/pro@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.1.31.tgz#cf2dc86643c52cb5655ffcc0f6a0f18125b032fd" - integrity sha512-Pvjd9DgEArFMe275GTC6q1sPuh/SNp9YPD0ckLkLsuNo3jp8f+FXjj5596dFbOxf7r2+Hg/v+f8tQFeslx1RFQ== +"@budibase/pro@1.1.33-alpha.0": + version "1.1.33-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.1.33-alpha.0.tgz#0ad6ab84a6e056bafa0ccd5a76310661ae8af216" + integrity sha512-8FQOewCDHpe7AL2psQ/VMy4YkwacQYg1dMnK9GMDFL6MGkgV2bPxOMDyOYgAUaDpwhXh7P9KIszysRinW/T5Dg== dependencies: - "@budibase/backend-core" "1.1.31" - "@budibase/types" "1.1.31" + "@budibase/backend-core" "1.1.33-alpha.0" + "@budibase/types" "1.1.33-alpha.0" + "@koa/router" "8.0.8" + joi "17.6.0" node-fetch "^2.6.1" "@budibase/standard-components@^0.9.139": @@ -1204,15 +1206,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.1.31.tgz#1bc323261627bdb2db06868a8666877cdd8d2e86" - integrity sha512-Nhv9xO24gWbCyBaLbndmh/uVliPIKGMDiQq/o2mub6gvFa8cMHmHZQ+j34qMxfVaMD3bSLQy5rPJptLxTs2XQg== - -"@budibase/types@^1.1.31": - version "1.1.32" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.1.32.tgz#b03acb9f287457c6ac51afbbf31da9f6e74ae70b" - integrity sha512-/e21ZtIkI/ks16RKQjMtfFUL5P3YQdSJBtqaCPlEiBQkIilFku+lc3GFB5rlvlBYqlzkJuq+ZQFII2oNFyJdYw== +"@budibase/types@1.1.33-alpha.0": + version "1.1.33-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.1.33-alpha.0.tgz#78f59d004bb3b201e04d9ad84583e64a98db40b9" + integrity sha512-ZEjdylzTfsxeOhZtVNxm+4cViq8SlpN6Dg8b3HoFQntXaIdGuD9M1GKVMd+juYBbcbNdx0GDu+UsVgVZLrosxQ== "@bull-board/api@3.7.0": version "3.7.0" @@ -2018,6 +2015,18 @@ path-to-regexp "^1.1.1" urijs "^1.19.0" +"@koa/router@8.0.8": + version "8.0.8" + resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236" + integrity sha512-FnT93N4NUehnXr+juupDmG2yfi0JnWdCmNEuIXpCG4TtG+9xvtrLambBH3RclycopVUOEYAim2lydiNBI7IRVg== + dependencies: + debug "^4.1.1" + http-errors "^1.7.3" + koa-compose "^4.1.0" + methods "^1.1.2" + path-to-regexp "1.x" + urijs "^1.19.2" + "@mapbox/node-pre-gyp@^1.0.0": version "1.0.9" resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" @@ -2237,6 +2246,23 @@ "@sentry/types" "6.17.7" tslib "^1.9.3" +"@sideway/address@^4.1.3": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -8658,6 +8684,17 @@ joi@17.2.1: "@hapi/pinpoint" "^2.0.0" "@hapi/topo" "^5.0.0" +joi@17.6.0: + version "17.6.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" + integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + join-component@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5" @@ -9178,10 +9215,10 @@ koa-views@^7.0.1: pretty "^2.0.0" resolve-path "^1.4.0" -koa2-ratelimit@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/koa2-ratelimit/-/koa2-ratelimit-1.1.0.tgz#5ab432fdda7b2d63a4fb1b9a0d994c1264396aff" - integrity sha512-AumRCI8YO9TMF9trVP6j68K5qzi21ajZUOCb5VuPWq9pZw+FHXam275S5P1IDAlZjs1cDFBOAAkhwTdTbVCcsg== +koa2-ratelimit@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/koa2-ratelimit/-/koa2-ratelimit-1.1.1.tgz#9c1d8257770e4a0a08063ba2ddcaf690fd457d23" + integrity sha512-IpxGMdZqEhMykW0yYKGVB4vDEacPvSBH4hNpDL38ABj3W2KHNLujAljGEDg7eEjXvrRbXRSWXzANhV3c9v7nyg== koa@2.7.0: version "2.7.0" @@ -10775,18 +10812,18 @@ path-parser@^6.1.0: search-params "3.0.0" tslib "^1.10.0" -path-to-regexp@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38" - integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg== - -path-to-regexp@^1.1.1: +path-to-regexp@1.x, path-to-regexp@^1.1.1: version "1.8.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== dependencies: isarray "0.0.1" +path-to-regexp@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38" + integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg== + path-to-regexp@^6.1.0, path-to-regexp@^6.2.0: version "6.2.1" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" @@ -12893,10 +12930,10 @@ svelte-portal@^1.0.0: resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== -svelte@3.44.1: - version "3.44.1" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.44.1.tgz#5cc772a8340f4519a4ecd1ac1a842325466b1a63" - integrity sha512-4DrCEJoBvdR689efHNSxIQn2pnFwB7E7j2yLEJtHE/P8hxwZWIphCtJ8are7bjl/iVMlcEf5uh5pJ68IwR09vQ== +svelte@3.49.0: + version "3.49.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" + integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== svg.draggable.js@^2.2.2: version "2.2.2" @@ -13668,7 +13705,7 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urijs@^1.19.0: +urijs@^1.19.0, urijs@^1.19.2: version "1.19.11" resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index c490158f27..20a095f088 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/string-templates/yarn.lock b/packages/string-templates/yarn.lock index ca434d6626..7647fa1928 100644 --- a/packages/string-templates/yarn.lock +++ b/packages/string-templates/yarn.lock @@ -515,6 +515,46 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@rollup/plugin-commonjs@^17.1.0": version "17.1.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz#757ec88737dffa8aa913eb392fade2e45aef2a2d" @@ -711,10 +751,10 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4, acorn@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +acorn@^8.2.4, acorn@^8.5.0, acorn@^8.7.0: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== agent-base@6: version "6.0.2" @@ -3956,9 +3996,9 @@ source-map-resolve@^0.5.0: urix "^0.1.0" source-map-support@^0.5.6, source-map-support@~0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -3978,7 +4018,7 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3, source-map@~0.7.2: +source-map@^0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== @@ -4145,12 +4185,13 @@ terminal-link@^2.0.0: supports-hyperlinks "^2.0.0" terser@^5.0.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" - integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== + version "5.14.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" + integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" source-map-support "~0.5.20" test-exclude@^6.0.0: diff --git a/packages/types/package.json b/packages/types/package.json index 4fdd508f3c..b01891f7c7 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/types/src/documents/app/automation.ts b/packages/types/src/documents/app/automation.ts index 97248ff173..50562461e4 100644 --- a/packages/types/src/documents/app/automation.ts +++ b/packages/types/src/documents/app/automation.ts @@ -12,6 +12,14 @@ export interface Automation extends Document { export interface AutomationStep { id: string stepId: string + inputs: { + [key: string]: any + } + schema: { + inputs: { + [key: string]: any + } + } } export interface AutomationTrigger { @@ -23,11 +31,12 @@ export enum AutomationStatus { SUCCESS = "success", ERROR = "error", STOPPED = "stopped", + STOPPED_ERROR = "stopped_error", } export interface AutomationResults { - automationId: string - status: string + automationId?: string + status?: AutomationStatus trigger?: any steps: { stepId: string diff --git a/packages/types/src/documents/global/index.ts b/packages/types/src/documents/global/index.ts index da01c73304..77785c72e4 100644 --- a/packages/types/src/documents/global/index.ts +++ b/packages/types/src/documents/global/index.ts @@ -1,2 +1,3 @@ export * from "./config" export * from "./user" +export * from "./userGroup" diff --git a/packages/types/src/documents/global/user.ts b/packages/types/src/documents/global/user.ts index 2de9ff7719..c9255a1bb1 100644 --- a/packages/types/src/documents/global/user.ts +++ b/packages/types/src/documents/global/user.ts @@ -14,6 +14,7 @@ export interface User extends Document { password?: string status?: string createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now() + userGroups?: string[] } export interface UserRoles { diff --git a/packages/types/src/documents/global/userGroup.ts b/packages/types/src/documents/global/userGroup.ts new file mode 100644 index 0000000000..b822e5bb7b --- /dev/null +++ b/packages/types/src/documents/global/userGroup.ts @@ -0,0 +1,19 @@ +import { Document } from "../document" +import { User } from "./user" +export interface UserGroup extends Document { + name: string + icon: string + color: string + users: groupUser[] + apps: string[] + roles: UserGroupRoles + createdAt?: number +} + +export interface groupUser { + _id: string + email: string[] +} +export interface UserGroupRoles { + [key: string]: string +} diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index 5dc1707fa7..f0e023df51 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -150,6 +150,15 @@ export enum Event { TENANT_BACKFILL_FAILED = "tenant:backfill:failed", INSTALLATION_BACKFILL_SUCCEEDED = "installation:backfill:succeeded", INSTALLATION_BACKFILL_FAILED = "installation:backfill:failed", + + // USER + USER_GROUP_CREATED = "user_group:created", + USER_GROUP_UPDATED = "user_group:updated", + USER_GROUP_DELETED = "user_group:deleted", + USER_GROUP_USERS_ADDED = "user_group:user_added", + USER_GROUP_USERS_REMOVED = "user_group:users_deleted", + USER_GROUP_PERMISSIONS_EDITED = "user_group:permissions_edited", + USER_GROUP_ONBOARDING = "user_group:onboarding_added", } // properties added at the final stage of the event pipeline diff --git a/packages/types/src/sdk/events/index.ts b/packages/types/src/sdk/events/index.ts index 5822f66597..88d5a12e6e 100644 --- a/packages/types/src/sdk/events/index.ts +++ b/packages/types/src/sdk/events/index.ts @@ -18,3 +18,4 @@ export * from "./view" export * from "./account" export * from "./backfill" export * from "./identification" +export * from "./userGroup" diff --git a/packages/types/src/sdk/events/userGroup.ts b/packages/types/src/sdk/events/userGroup.ts new file mode 100644 index 0000000000..2ce642e274 --- /dev/null +++ b/packages/types/src/sdk/events/userGroup.ts @@ -0,0 +1,28 @@ +import { BaseEvent } from "./event" + +export interface GroupCreatedEvent extends BaseEvent { + groupId: string +} + +export interface GroupUpdatedEvent extends BaseEvent { + groupId: string +} + +export interface GroupDeletedEvent extends BaseEvent { + groupId: string +} + +export interface GroupUsersAddedEvent extends BaseEvent { + count: number + groupId: string +} + +export interface GroupUsersDeletedEvent extends BaseEvent { + count: number + groupId: string +} + +export interface GroupAddedOnboardingEvent extends BaseEvent { + groupId: string + onboarding: boolean +} diff --git a/packages/worker/package.json b/packages/worker/package.json index 79c8bf0be1..a3eaaa5af5 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "1.1.31", + "version": "1.1.33-alpha.0", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -35,10 +35,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "^1.1.31", - "@budibase/pro": "1.1.31", - "@budibase/string-templates": "^1.1.31", - "@budibase/types": "^1.1.31", + "@budibase/backend-core": "1.1.33-alpha.0", + "@budibase/pro": "1.1.33-alpha.0", + "@budibase/string-templates": "1.1.33-alpha.0", + "@budibase/types": "1.1.33-alpha.0", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index 5e3b3accb4..17e655edb3 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -13,6 +13,8 @@ import { cache, } from "@budibase/backend-core" import { checkAnyUserExists } from "../../../utilities/users" +import { groups as groupUtils } from "@budibase/pro" +const MAX_USERS_UPLOAD_LIMIT = 1000 export const save = async (ctx: any) => { try { @@ -22,6 +24,36 @@ export const save = async (ctx: any) => { } } +export const bulkCreate = async (ctx: any) => { + let { users: newUsersRequested, groups } = ctx.request.body + + if (!env.SELF_HOSTED && newUsersRequested.length > MAX_USERS_UPLOAD_LIMIT) { + ctx.throw( + 400, + "Max limit for upload is 1000 users. Please reduce file size and try again." + ) + } + + const db = tenancy.getGlobalDB() + let groupsToSave: any[] = [] + + if (groups.length) { + for (const groupId of groups) { + let oldGroup = await db.get(groupId) + groupsToSave.push(oldGroup) + } + } + + try { + let response = await users.bulkCreate(newUsersRequested, groups) + await groupUtils.bulkSaveGroupUsers(groupsToSave, response) + + ctx.body = response + } catch (err: any) { + ctx.throw(err.status || 400, err) + } +} + const parseBooleanParam = (param: any) => { return !(param && param === "false") } @@ -82,14 +114,39 @@ export const adminUser = async (ctx: any) => { }) } +export const countByApp = async (ctx: any) => { + const appId = ctx.params.appId + try { + const response = await users.countUsersByApp(appId) + ctx.body = response + } catch (err: any) { + ctx.throw(err.status || 400, err) + } +} + export const destroy = async (ctx: any) => { const id = ctx.params.id + await users.destroy(id, ctx.user) + ctx.body = { message: `User ${id} deleted.`, } } +export const bulkDelete = async (ctx: any) => { + const { userIds } = ctx.request.body + try { + let usersResponse = await users.bulkDelete(userIds) + + ctx.body = { + message: `${usersResponse.length} user(s) deleted`, + } + } catch (err) { + ctx.throw(err) + } +} + export const search = async (ctx: any) => { const paginated = await users.paginatedUsers(ctx.request.body) // user hashed password shouldn't ever be returned @@ -149,6 +206,39 @@ export const invite = async (ctx: any) => { await events.user.invited() } +export const inviteMultiple = async (ctx: any) => { + let { emails, userInfo } = ctx.request.body + let existing = false + let existingEmail + for (let email of emails) { + if (await usersCore.getGlobalUserByEmail(email)) { + existing = true + existingEmail = email + break + } + } + + if (existing) { + ctx.throw(400, `${existingEmail} already exists`) + } + if (!userInfo) { + userInfo = {} + } + userInfo.tenantId = tenancy.getTenantId() + const opts: any = { + subject: "{{ company }} platform invitation", + info: userInfo, + } + + for (let i = 0; i < emails.length; i++) { + await sendEmail(emails[i], EmailTemplatePurpose.INVITATION, opts) + } + + ctx.body = { + message: "Invitations have been sent.", + } +} + export const inviteAccept = async (ctx: any) => { const { inviteCode, password, firstName, lastName } = ctx.request.body try { diff --git a/packages/worker/src/api/routes/global/auth.js b/packages/worker/src/api/routes/global/auth.js index cc00b4f82f..07d95f808d 100644 --- a/packages/worker/src/api/routes/global/auth.js +++ b/packages/worker/src/api/routes/global/auth.js @@ -1,6 +1,6 @@ const Router = require("@koa/router") const authController = require("../../controllers/global/auth") -const joiValidator = require("../../../middleware/joi-validator") +const { joiValidator } = require("@budibase/backend-core/auth") const Joi = require("joi") const { updateTenantId } = require("@budibase/backend-core/tenancy") diff --git a/packages/worker/src/api/routes/global/configs.js b/packages/worker/src/api/routes/global/configs.js index 5505d03753..c4beb57600 100644 --- a/packages/worker/src/api/routes/global/configs.js +++ b/packages/worker/src/api/routes/global/configs.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../../controllers/global/configs") -const joiValidator = require("../../../middleware/joi-validator") -const adminOnly = require("../../../middleware/adminOnly") +const { joiValidator } = require("@budibase/backend-core/auth") +const { adminOnly } = require("@budibase/backend-core/auth") const Joi = require("joi") const { Configs } = require("../../../constants") @@ -65,6 +65,8 @@ function buildConfigSaveValidation() { _rev: Joi.string().optional(), workspace: Joi.string().optional(), type: Joi.string().valid(...Object.values(Configs)).required(), + createdAt: Joi.string().optional(), + updatedAt: Joi.string().optional(), config: Joi.alternatives() .conditional("type", { switch: [ @@ -75,7 +77,7 @@ function buildConfigSaveValidation() { { is: Configs.OIDC, then: oidcValidation() } ], }), - }).required().unknown(true), + }).required().unknown(true), ) } diff --git a/packages/worker/src/api/routes/global/email.js b/packages/worker/src/api/routes/global/email.js index fecbc02cd7..b771728a0f 100644 --- a/packages/worker/src/api/routes/global/email.js +++ b/packages/worker/src/api/routes/global/email.js @@ -1,8 +1,8 @@ const Router = require("@koa/router") const controller = require("../../controllers/global/email") const { EmailTemplatePurpose } = require("../../../constants") -const joiValidator = require("../../../middleware/joi-validator") -const adminOnly = require("../../../middleware/adminOnly") +const { joiValidator } = require("@budibase/backend-core/auth") +const { adminOnly } = require("@budibase/backend-core/auth") const Joi = require("joi") const router = Router() diff --git a/packages/worker/src/api/routes/global/roles.js b/packages/worker/src/api/routes/global/roles.js index ab79883ab8..4e27b7d54b 100644 --- a/packages/worker/src/api/routes/global/roles.js +++ b/packages/worker/src/api/routes/global/roles.js @@ -1,6 +1,6 @@ const Router = require("@koa/router") const controller = require("../../controllers/global/roles") -const adminOnly = require("../../../middleware/adminOnly") +const { adminOnly } = require("@budibase/backend-core/auth") const router = Router() diff --git a/packages/worker/src/api/routes/global/sessions.js b/packages/worker/src/api/routes/global/sessions.js index 5ba6747e68..6ab4ad8e59 100644 --- a/packages/worker/src/api/routes/global/sessions.js +++ b/packages/worker/src/api/routes/global/sessions.js @@ -1,6 +1,6 @@ const Router = require("@koa/router") const controller = require("../../controllers/global/sessions") -const adminOnly = require("../../../middleware/adminOnly") +const { adminOnly } = require("@budibase/backend-core/auth") const router = Router() diff --git a/packages/worker/src/api/routes/global/templates.js b/packages/worker/src/api/routes/global/templates.js index e4580d444c..321e0543ad 100644 --- a/packages/worker/src/api/routes/global/templates.js +++ b/packages/worker/src/api/routes/global/templates.js @@ -1,9 +1,9 @@ const Router = require("@koa/router") const controller = require("../../controllers/global/templates") -const joiValidator = require("../../../middleware/joi-validator") +const { joiValidator } = require("@budibase/backend-core/auth") const Joi = require("joi") const { TemplatePurpose, TemplateTypes } = require("../../../constants") -const adminOnly = require("../../../middleware/adminOnly") +const { adminOnly } = require("@budibase/backend-core/auth") const router = Router() diff --git a/packages/worker/src/api/routes/global/users.js b/packages/worker/src/api/routes/global/users.js index da89ad20eb..e62e996443 100644 --- a/packages/worker/src/api/routes/global/users.js +++ b/packages/worker/src/api/routes/global/users.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../../controllers/global/users") -const joiValidator = require("../../../middleware/joi-validator") -const adminOnly = require("../../../middleware/adminOnly") +const { joiValidator } = require("@budibase/backend-core/auth") +const { adminOnly } = require("@budibase/backend-core/auth") const Joi = require("joi") const cloudRestricted = require("../../../middleware/cloudRestricted") const { users } = require("../validation") @@ -30,6 +30,14 @@ function buildInviteValidation() { }).required()) } +function buildInviteMultipleValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + emails: Joi.array().required(), + userInfo: Joi.object().optional(), + }).required()) +} + function buildInviteAcceptValidation() { // prettier-ignore return joiValidator.body(Joi.object({ @@ -45,9 +53,18 @@ router users.buildUserSaveValidation(), controller.save ) + .post( + "/api/global/users/bulkCreate", + adminOnly, + users.buildUserBulkSaveValidation(), + controller.bulkCreate + ) + .get("/api/global/users", builderOrAdmin, controller.fetch) .post("/api/global/users/search", builderOrAdmin, controller.search) .delete("/api/global/users/:id", adminOnly, controller.destroy) + .post("/api/global/users/bulkDelete", adminOnly, controller.bulkDelete) + .get("/api/global/users/count/:appId", adminOnly, controller.countByApp) .get("/api/global/roles/:appId") .post( "/api/global/users/invite", @@ -55,6 +72,19 @@ router buildInviteValidation(), controller.invite ) + .post( + "/api/global/users/invite", + adminOnly, + buildInviteValidation(), + controller.invite + ) + .post( + "/api/global/users/inviteMultiple", + adminOnly, + buildInviteMultipleValidation(), + controller.inviteMultiple + ) + // non-global endpoints .post( "/api/global/users/invite/accept", diff --git a/packages/worker/src/api/routes/global/workspaces.js b/packages/worker/src/api/routes/global/workspaces.js index cab76b7763..0198991bfa 100644 --- a/packages/worker/src/api/routes/global/workspaces.js +++ b/packages/worker/src/api/routes/global/workspaces.js @@ -1,7 +1,7 @@ const Router = require("@koa/router") const controller = require("../../controllers/global/workspaces") -const joiValidator = require("../../../middleware/joi-validator") -const adminOnly = require("../../../middleware/adminOnly") +const { joiValidator } = require("@budibase/backend-core/auth") +const { adminOnly } = require("@budibase/backend-core/auth") const Joi = require("joi") const router = Router() @@ -17,9 +17,9 @@ function buildWorkspaceSaveValidation() { roles: Joi.object({ default: Joi.string().optional(), app: Joi.object() - .pattern(/.*/, Joi.string()) - .required() - .unknown(true), + .pattern(/.*/, Joi.string()) + .required() + .unknown(true), }).unknown(true).optional(), }).required().unknown(true)) } diff --git a/packages/worker/src/api/routes/index.js b/packages/worker/src/api/routes/index.js index c351455a0d..89c67bdf88 100644 --- a/packages/worker/src/api/routes/index.js +++ b/packages/worker/src/api/routes/index.js @@ -1,3 +1,4 @@ +const { api } = require("@budibase/pro") const userRoutes = require("./global/users") const configRoutes = require("./global/configs") const workspaceRoutes = require("./global/workspaces") @@ -12,6 +13,7 @@ const statusRoutes = require("./system/status") const selfRoutes = require("./global/self") const licenseRoutes = require("./global/license") +let userGroupRoutes = api.groups exports.routes = [ configRoutes, userRoutes, @@ -26,4 +28,5 @@ exports.routes = [ statusRoutes, selfRoutes, licenseRoutes, + userGroupRoutes, ] diff --git a/packages/worker/src/api/routes/system/tenants.js b/packages/worker/src/api/routes/system/tenants.js index 49c7509a67..451f09f773 100644 --- a/packages/worker/src/api/routes/system/tenants.js +++ b/packages/worker/src/api/routes/system/tenants.js @@ -1,6 +1,6 @@ const Router = require("@koa/router") const controller = require("../../controllers/system/tenants") -const adminOnly = require("../../../middleware/adminOnly") +const { adminOnly } = require("@budibase/backend-core/auth") const router = Router() diff --git a/packages/worker/src/api/routes/tests/users.spec.js b/packages/worker/src/api/routes/tests/users.spec.js index 62cc02fde8..5813dd3852 100644 --- a/packages/worker/src/api/routes/tests/users.spec.js +++ b/packages/worker/src/api/routes/tests/users.spec.js @@ -2,7 +2,6 @@ jest.mock("nodemailer") const { config, request, mocks, structures } = require("../../../tests") const sendMailMock = mocks.email.mock() const { events } = require("@budibase/backend-core") - describe("/api/global/users", () => { beforeAll(async () => { @@ -24,9 +23,9 @@ describe("/api/global/users", () => { .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) - - const emailCall = sendMailMock.mock.calls[0][0] - // after this URL there should be a code + + const emailCall = sendMailMock.mock.calls[0][0] + // after this URL there should be a code const parts = emailCall.html.split("http://localhost:10000/builder/invite?code=") const code = parts[1].split("\"")[0].split("&")[0] return { code, res } @@ -60,7 +59,7 @@ describe("/api/global/users", () => { expect(events.user.inviteAccepted).toBeCalledWith(user) }) - const createUser = async (user) => { + const createUser = async (user) => { const existing = await config.getUser(user.email) if (existing) { await deleteUser(existing._id) @@ -84,14 +83,37 @@ describe("/api/global/users", () => { return res.body } + + const bulkCreateUsers = async (users) => { + const res = await request + .post(`/api/global/users/bulkCreate`) + .send(users) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + return res.body + } + + const bulkDeleteUsers = async (users) => { + const res = await request + .post(`/api/global/users/bulkDelete`) + .send(users) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + return res.body + } + + + const deleteUser = async (email) => { const user = await config.getUser(email) if (user) { await request - .delete(`/api/global/users/${user._id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + .delete(`/api/global/users/${user._id}`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) } } @@ -107,10 +129,25 @@ describe("/api/global/users", () => { expect(events.user.permissionAdminAssigned).not.toBeCalled() }) + it("should be able to bulkCreate users with different permissions", async () => { + jest.clearAllMocks() + const builder = structures.users.builderUser({ email: "bulkbasic@test.com" }) + const admin = structures.users.adminUser({ email: "bulkadmin@test.com" }) + const user = structures.users.user({ email: "bulkuser@test.com" }) + + let toCreate = { users: [builder, admin, user], groups: [] } + await bulkCreateUsers(toCreate) + + expect(events.user.created).toBeCalledTimes(3) + expect(events.user.permissionAdminAssigned).toBeCalledTimes(1) + expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1) + }) + + it("should be able to create an admin user", async () => { jest.clearAllMocks() const user = structures.users.adminUser({ email: "admin@test.com" }) - await createUser(user) + await createUser(user) expect(events.user.created).toBeCalledTimes(1) expect(events.user.updated).not.toBeCalled() @@ -333,5 +370,21 @@ describe("/api/global/users", () => { expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1) expect(events.user.permissionAdminRemoved).not.toBeCalled() }) + + it("should be able to bulk delete users with different permissions", async () => { + jest.clearAllMocks() + const builder = structures.users.builderUser({ email: "basic@test.com" }) + const admin = structures.users.adminUser({ email: "admin@test.com" }) + const user = structures.users.user({ email: "user@test.com" }) + + let toCreate = { users: [builder, admin, user], groups: [] } + let createdUsers = await bulkCreateUsers(toCreate) + await bulkDeleteUsers({ userIds: [createdUsers[0]._id, createdUsers[1]._id, createdUsers[2]._id] }) + expect(events.user.deleted).toBeCalledTimes(3) + expect(events.user.permissionAdminRemoved).toBeCalledTimes(1) + expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1) + + }) + }) }) \ No newline at end of file diff --git a/packages/worker/src/api/routes/validation/users.ts b/packages/worker/src/api/routes/validation/users.ts index 81372358ff..e7ad4cca18 100644 --- a/packages/worker/src/api/routes/validation/users.ts +++ b/packages/worker/src/api/routes/validation/users.ts @@ -1,22 +1,23 @@ import joiValidator from "../../../middleware/joi-validator" import Joi from "joi" +let schema: any = { + email: Joi.string().allow(null, ""), + password: Joi.string().allow(null, ""), + forceResetPassword: Joi.boolean().optional(), + firstName: Joi.string().allow(null, ""), + lastName: Joi.string().allow(null, ""), + builder: Joi.object({ + global: Joi.boolean().optional(), + apps: Joi.array().optional(), + }) + .unknown(true) + .optional(), + // maps appId -> roleId for the user + roles: Joi.object().pattern(/.*/, Joi.string()).required().unknown(true), +} + export const buildUserSaveValidation = (isSelf = false) => { - let schema: any = { - email: Joi.string().allow(null, ""), - password: Joi.string().allow(null, ""), - forceResetPassword: Joi.boolean().optional(), - firstName: Joi.string().allow(null, ""), - lastName: Joi.string().allow(null, ""), - builder: Joi.object({ - global: Joi.boolean().optional(), - apps: Joi.array().optional(), - }) - .unknown(true) - .optional(), - // maps appId -> roleId for the user - roles: Joi.object().pattern(/.*/, Joi.string()).required().unknown(true), - } if (!isSelf) { schema = { ...schema, @@ -26,3 +27,19 @@ export const buildUserSaveValidation = (isSelf = false) => { } return joiValidator.body(Joi.object(schema).required().unknown(true)) } + +export const buildUserBulkSaveValidation = (isSelf = false) => { + if (!isSelf) { + schema = { + ...schema, + _id: Joi.string(), + _rev: Joi.string(), + } + } + let bulkSaveSchema = { + groups: Joi.array().optional(), + users: Joi.array().items(Joi.object(schema).required().unknown(true)), + } + + return joiValidator.body(Joi.object(bulkSaveSchema).required().unknown(true)) +} diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 35a4083df9..ea7f2517e0 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -15,7 +15,8 @@ import { accounts, migrations, } from "@budibase/backend-core" -import { MigrationType } from "@budibase/types" +import { MigrationType, User } from "@budibase/types" +import { groups as groupUtils } from "@budibase/pro" const PAGE_LIMIT = 8 @@ -29,10 +30,18 @@ export const allUsers = async () => { return response.rows.map((row: any) => row.doc) } +export const countUsersByApp = async (appId: string) => { + let response: any = await usersCore.searchGlobalUsersByApp(appId, {}) + return { + userCount: response.length, + } +} + export const paginatedUsers = async ({ page, - search, -}: { page?: string; search?: string } = {}) => { + email, + appId, +}: { page?: string; email?: string; appId?: string } = {}) => { const db = tenancy.getGlobalDB() // get one extra document, to have the next page const opts: any = { @@ -44,19 +53,24 @@ export const paginatedUsers = async ({ opts.startkey = page } // property specifies what to use for the page/anchor - let userList, property - // no search, query allDocs - if (!search) { + let userList, + property = "_id", + getKey + if (appId) { + userList = await usersCore.searchGlobalUsersByApp(appId, opts) + getKey = (doc: any) => usersCore.getGlobalUserByAppPage(appId, doc) + } else if (email) { + userList = await usersCore.searchGlobalUsersByEmail(email, opts) + property = "email" + } else { + // no search, query allDocs const response = await db.allDocs(dbUtils.getGlobalUserParams(null, opts)) userList = response.rows.map((row: any) => row.doc) - property = "_id" - } else { - userList = await usersCore.searchGlobalUsersByEmail(search, opts) - property = "email" } return dbUtils.pagination(userList, PAGE_LIMIT, { paginate: true, property, + getKey, }) } @@ -87,6 +101,49 @@ interface SaveUserOpts { bulkCreate?: boolean } +export const buildUser = async ( + user: any, + opts: SaveUserOpts = { + hashPassword: true, + requirePassword: true, + bulkCreate: false, + }, + tenantId: string, + dbUser?: any +) => { + let { password, _id } = user + + let hashedPassword + if (password) { + hashedPassword = opts.hashPassword ? await utils.hash(password) : password + } else if (dbUser) { + hashedPassword = dbUser.password + } else if (opts.requirePassword) { + throw "Password must be specified." + } + + _id = _id || dbUtils.generateGlobalUserID() + + user = { + createdAt: Date.now(), + ...dbUser, + ...user, + _id, + password: hashedPassword, + tenantId, + } + // make sure the roles object is always present + if (!user.roles) { + user.roles = {} + } + // add the active status to a user if its not provided + if (user.status == null) { + user.status = constants.UserStatus.ACTIVE + } + + return user +} + export const save = async ( user: any, opts: SaveUserOpts = { @@ -97,7 +154,7 @@ export const save = async ( ) => { const tenantId = tenancy.getTenantId() const db = tenancy.getGlobalDB() - let { email, password, _id } = user + let { email, _id } = user // make sure another user isn't using the same email let dbUser: any if (opts.bulkCreate) { @@ -128,36 +185,19 @@ export const save = async ( dbUser = await db.get(_id) } - // get the password, make sure one is defined - let hashedPassword - if (password) { - hashedPassword = opts.hashPassword ? await utils.hash(password) : password - } else if (dbUser) { - hashedPassword = dbUser.password - } else if (opts.requirePassword) { - throw "Password must be specified." - } - - _id = _id || dbUtils.generateGlobalUserID() - user = { - createdAt: Date.now(), - ...dbUser, - ...user, - _id, - password: hashedPassword, + let builtUser = await buildUser( + user, + { + hashPassword: true, + requirePassword: user.requirePassword, + }, tenantId, - } - // make sure the roles object is always present - if (!user.roles) { - user.roles = {} - } - // add the active status to a user if its not provided - if (user.status == null) { - user.status = constants.UserStatus.ACTIVE - } + dbUser + ) + try { const putOpts = { - password: hashedPassword, + password: builtUser.password, ...user, } if (opts.bulkCreate) { @@ -166,28 +206,21 @@ export const save = async ( // save the user to db let response const putUserFn = () => { - return db.put(user) + return db.put(builtUser) } - if (eventHelpers.isAddingBuilder(user, dbUser)) { + + if (eventHelpers.isAddingBuilder(builtUser, dbUser)) { response = await quotas.addDeveloper(putUserFn) } else { response = await putUserFn() } - user._rev = response.rev + builtUser._rev = response.rev - await eventHelpers.handleSaveEvents(user, dbUser) - - if (env.MULTI_TENANCY) { - const afterCreateTenant = () => - migrations.backPopulateMigrations({ - type: MigrationType.GLOBAL, - tenantId, - }) - await tenancy.tryAddTenant(tenantId, _id, email, afterCreateTenant) - } + await eventHelpers.handleSaveEvents(builtUser, dbUser) + await addTenant(tenantId, _id, email) await cache.user.invalidateUser(response.id) // let server know to sync user - await apps.syncUserInApps(user._id) + await apps.syncUserInApps(builtUser._id) return { _id: response.id, @@ -203,9 +236,143 @@ export const save = async ( } } +export const addTenant = async ( + tenantId: string, + _id: string, + email: string +) => { + if (env.MULTI_TENANCY) { + const afterCreateTenant = () => + migrations.backPopulateMigrations({ + type: MigrationType.GLOBAL, + tenantId, + }) + await tenancy.tryAddTenant(tenantId, _id, email, afterCreateTenant) + } +} + +export const bulkCreate = async ( + newUsersRequested: User[], + groups: string[] +) => { + const db = tenancy.getGlobalDB() + const tenantId = tenancy.getTenantId() + + let usersToSave: any[] = [] + let newUsers: any[] = [] + + const allUsers = await db.allDocs( + dbUtils.getGlobalUserParams(null, { + include_docs: true, + }) + ) + let mapped = allUsers.rows.map((row: any) => row.id) + + const currentUserEmails = mapped.map((x: any) => x.email) || [] + for (const newUser of newUsersRequested) { + if ( + newUsers.find((x: any) => x.email === newUser.email) || + currentUserEmails.includes(newUser.email) + ) { + continue + } + newUser.userGroups = groups + newUsers.push(newUser) + } + + // Figure out how many builders we are adding and create the promises + // array that will be called by bulkDocs + let builderCount = 0 + newUsers.forEach((user: any) => { + if (eventHelpers.isAddingBuilder(user, null)) { + builderCount++ + } + usersToSave.push( + buildUser( + user, + { + hashPassword: true, + requirePassword: user.requirePassword, + bulkCreate: false, + }, + tenantId + ) + ) + }) + + const usersToBulkSave = await Promise.all(usersToSave) + await quotas.addDevelopers(() => db.bulkDocs(usersToBulkSave), builderCount) + + // Post processing of bulk added users, i.e events and cache operations + for (const user of usersToBulkSave) { + await eventHelpers.handleSaveEvents(user, null) + await apps.syncUserInApps(user._id) + } + + return usersToBulkSave.map(user => { + return { + _id: user._id, + email: user.email, + } + }) +} + +export const bulkDelete = async (userIds: any) => { + const db = tenancy.getGlobalDB() + + let groupsToModify: any = {} + let builderCount = 0 + // Get users and delete + let usersToDelete = ( + await db.allDocs({ + include_docs: true, + keys: userIds, + }) + ).rows.map((user: any) => { + // if we find a user that has an associated group, add it to + // an array so we can easily use allDocs on them later. + // This prevents us having to re-loop over all the users + if (user.doc.userGroups) { + for (let groupId of user.doc.userGroups) { + if (!Object.keys(groupsToModify).includes(groupId)) { + groupsToModify[groupId] = [user.id] + } else { + groupsToModify[groupId] = [...groupsToModify[groupId], user.id] + } + } + } + + // Also figure out how many builders are being deleted + if (eventHelpers.isAddingBuilder(user.doc, null)) { + builderCount++ + } + + return user.doc + }) + + const response = await db.bulkDocs( + usersToDelete.map((user: any) => ({ + ...user, + _deleted: true, + })) + ) + + await groupUtils.bulkDeleteGroupUsers(groupsToModify) + + //Deletion post processing + for (let user of usersToDelete) { + await bulkDeleteProcessing(user) + } + + await quotas.removeDevelopers(builderCount) + + return response +} + export const destroy = async (id: string, currentUser: any) => { const db = tenancy.getGlobalDB() const dbUser = await db.get(id) + let groups = dbUser.userGroups if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { // root account holder can't be deleted from inside budibase @@ -221,7 +388,13 @@ export const destroy = async (id: string, currentUser: any) => { } await deprovisioning.removeUserFromInfoDB(dbUser) + await db.remove(dbUser._id, dbUser._rev) + + if (groups) { + await groupUtils.deleteGroupUsers(groups, dbUser) + } + await eventHelpers.handleDeleteEvents(dbUser) await quotas.removeUser(dbUser) await cache.user.invalidateUser(dbUser._id) @@ -229,3 +402,12 @@ export const destroy = async (id: string, currentUser: any) => { // let server know to sync user await apps.syncUserInApps(dbUser._id) } + +const bulkDeleteProcessing = async (dbUser: User) => { + await deprovisioning.removeUserFromInfoDB(dbUser) + await eventHelpers.handleDeleteEvents(dbUser) + await cache.user.invalidateUser(dbUser._id) + await sessions.invalidateSessions(dbUser._id) + // let server know to sync user + await apps.syncUserInApps(dbUser._id) +} diff --git a/packages/worker/src/tests/TestConfiguration.js b/packages/worker/src/tests/TestConfiguration.js index 9c45217e3e..694c56bfcd 100644 --- a/packages/worker/src/tests/TestConfiguration.js +++ b/packages/worker/src/tests/TestConfiguration.js @@ -11,7 +11,7 @@ const { createASession } = require("@budibase/backend-core/sessions") const { TENANT_ID, CSRF_TOKEN } = require("./structures") const structures = require("./structures") const { doInTenant } = require("@budibase/backend-core/tenancy") - +const { groups } = require("@budibase/pro") class TestConfiguration { constructor(openServer = true) { if (openServer) { @@ -116,6 +116,22 @@ class TestConfiguration { }) } + async getGroup(id) { + return doInTenant(TENANT_ID, () => { + return groups.get(id) + }) + } + + async saveGroup(group) { + const res = await this.getRequest() + .post(`/api/global/groups`) + .send(group) + .set(this.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + return res.body + } + async createUser(email, password) { const user = await this.getUser(structures.users.email) if (user) { diff --git a/packages/worker/src/tests/structures/groups.ts b/packages/worker/src/tests/structures/groups.ts new file mode 100644 index 0000000000..874d1b6a10 --- /dev/null +++ b/packages/worker/src/tests/structures/groups.ts @@ -0,0 +1,11 @@ +export const UserGroup = () => { + let group = { + apps: [], + color: "var(--spectrum-global-color-blue-600)", + icon: "UserGroup", + name: "New group", + roles: {}, + users: [], + } + return group +} diff --git a/packages/worker/src/tests/structures/index.js b/packages/worker/src/tests/structures/index.js index 115d22e731..3212ae606d 100644 --- a/packages/worker/src/tests/structures/index.js +++ b/packages/worker/src/tests/structures/index.js @@ -1,5 +1,6 @@ const configs = require("./configs") const users = require("./users") +const groups = require("./groups") const TENANT_ID = "default" const CSRF_TOKEN = "e3727778-7af0-4226-b5eb-f43cbe60a306" @@ -9,4 +10,5 @@ module.exports = { users, TENANT_ID, CSRF_TOKEN, + groups, } diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index ae3910ed1e..06b1ea851c 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -185,14 +185,20 @@ exports.sendEmail = async ( // if there is a link code needed this will retrieve it const code = await getLinkCode(purpose, email, user, info) const context = await getSettingsTemplateContext(purpose, code) - const message = { + + let message = { from: from || config.from, - to: email, html: await buildEmail(purpose, email, context, { user, contents, }), } + + message = { + ...message, + to: email, + } + if (subject || config.subject) { message.subject = await processString(subject || config.subject, context) } diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 28af6fb948..961a3d13bc 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -291,12 +291,12 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.1.31.tgz#914283af0928ced36303ad4919e52314a8f68022" - integrity sha512-Uo2CxX87u8Lq5MyYOVAXw/wmawUAAUnWkJ648RR1v8CikjOpOixjIiIwb8fXOr1No2SwD4HjY/V/xZGXCgxilQ== +"@budibase/backend-core@1.1.33-alpha.0": + version "1.1.33-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.1.33-alpha.0.tgz#8a502a038c3a86fa061bc53c9538deed0598b96c" + integrity sha512-QSUX8sOHMip2XYbjAehhcFHpHucCOAQOR8sW20WDjofR/+DEHRuvkHXetgJvcl0CMPey8dmh98H+yeQio1kYcQ== dependencies: - "@budibase/types" "^1.1.31" + "@budibase/types" "1.1.33-alpha.0" "@techpass/passport-openidconnect" "0.3.2" aws-sdk "2.1030.0" bcrypt "5.0.1" @@ -324,24 +324,21 @@ uuid "8.3.2" zlib "1.0.5" -"@budibase/pro@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.1.31.tgz#cf2dc86643c52cb5655ffcc0f6a0f18125b032fd" - integrity sha512-Pvjd9DgEArFMe275GTC6q1sPuh/SNp9YPD0ckLkLsuNo3jp8f+FXjj5596dFbOxf7r2+Hg/v+f8tQFeslx1RFQ== +"@budibase/pro@1.1.33-alpha.0": + version "1.1.33-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.1.33-alpha.0.tgz#0ad6ab84a6e056bafa0ccd5a76310661ae8af216" + integrity sha512-8FQOewCDHpe7AL2psQ/VMy4YkwacQYg1dMnK9GMDFL6MGkgV2bPxOMDyOYgAUaDpwhXh7P9KIszysRinW/T5Dg== dependencies: - "@budibase/backend-core" "1.1.31" - "@budibase/types" "1.1.31" + "@budibase/backend-core" "1.1.33-alpha.0" + "@budibase/types" "1.1.33-alpha.0" + "@koa/router" "8.0.8" + joi "17.6.0" node-fetch "^2.6.1" -"@budibase/types@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.1.31.tgz#1bc323261627bdb2db06868a8666877cdd8d2e86" - integrity sha512-Nhv9xO24gWbCyBaLbndmh/uVliPIKGMDiQq/o2mub6gvFa8cMHmHZQ+j34qMxfVaMD3bSLQy5rPJptLxTs2XQg== - -"@budibase/types@^1.1.31": - version "1.1.32" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.1.32.tgz#b03acb9f287457c6ac51afbbf31da9f6e74ae70b" - integrity sha512-/e21ZtIkI/ks16RKQjMtfFUL5P3YQdSJBtqaCPlEiBQkIilFku+lc3GFB5rlvlBYqlzkJuq+ZQFII2oNFyJdYw== +"@budibase/types@1.1.33-alpha.0": + version "1.1.33-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.1.33-alpha.0.tgz#78f59d004bb3b201e04d9ad84583e64a98db40b9" + integrity sha512-ZEjdylzTfsxeOhZtVNxm+4cViq8SlpN6Dg8b3HoFQntXaIdGuD9M1GKVMd+juYBbcbNdx0GDu+UsVgVZLrosxQ== "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" diff --git a/scripts/pro/release.sh b/scripts/pro/release.sh index fc1d8132d9..a87ea5d10b 100755 --- a/scripts/pro/release.sh +++ b/scripts/pro/release.sh @@ -45,6 +45,14 @@ jq '.dependencies."@budibase/types"="'$VERSION'"' package.json > package.json.tm # Go back to pro repo root cd - +# Update lockfile with new dependency versions +yarn clean -y && yarn bootstrap + +# Commit and push +git add packages/pro/yarn.lock +git commit -m "Update dependency versions to $VERSION" +git push + ############################################# # PUBLISH # ############################################# @@ -88,8 +96,13 @@ jq '.dependencies."@budibase/pro"="'$VERSION'"' package.json > package.json.tmp # Go back to budibase repo root cd - +# Update lockfile with new pro version +yarn clean -y && yarn bootstrap + # Commit and push changes git add packages/server/package.json +git add packages/server/yarn.lock git add packages/worker/package.json +git add packages/worker/yarn.lock git commit -m "Update pro version to $VERSION" git push diff --git a/yarn.lock b/yarn.lock index feb39fd738..7df006e0fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5770,9 +5770,9 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== svelte@^3.38.2: - version "3.46.4" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.46.4.tgz#0c46bc4a3e20a2617a1b7dc43a722f9d6c084a38" - integrity sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg== + version "3.49.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" + integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== table@^6.0.9: version "6.8.0"