diff --git a/charts/budibase/values.yaml b/charts/budibase/values.yaml index be0612299c..5ada89de6c 100644 --- a/charts/budibase/values.yaml +++ b/charts/budibase/values.yaml @@ -47,6 +47,8 @@ ingress: className: "" annotations: kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/client-max-body-size: 150M + nginx.ingress.kubernetes.io/proxy-body-size: 50m hosts: - host: # change if using custom domain paths: diff --git a/lerna.json b/lerna.json index a770e97ced..96440d2573 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.0.105-alpha.45", + "version": "1.0.122", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index 3e6290e40b..727104d830 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "mode:account": "yarn mode:cloud && yarn env:account:enable", "security:audit": "node scripts/audit.js", "postinstall": "husky install", - "install:pro": "bash scripts/pro/install.sh" + "install:pro": "bash scripts/pro/install.sh", + "dep:clean": "yarn clean && yarn bootstrap" } } diff --git a/packages/backend-core/db.js b/packages/backend-core/db.js index d2adf6c092..0d2869d9f1 100644 --- a/packages/backend-core/db.js +++ b/packages/backend-core/db.js @@ -3,4 +3,5 @@ module.exports = { ...require("./src/db/constants"), ...require("./src/db"), ...require("./src/db/views"), + ...require("./src/db/pouch"), } diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 71e484d9af..322c81d402 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "description": "Budibase backend core libraries used in server and worker", "main": "src/index.js", "author": "Budibase", @@ -24,6 +24,10 @@ "passport-google-oauth": "^2.0.0", "passport-jwt": "^4.0.0", "passport-local": "^1.0.0", + "posthog-node": "^1.3.0", + "pouchdb": "7.3.0", + "pouchdb-find": "^7.2.2", + "pouchdb-replication-stream": "^1.2.9", "sanitize-s3-objectkey": "^0.0.1", "tar-fs": "^2.1.1", "uuid": "^8.3.2", @@ -37,7 +41,6 @@ "devDependencies": { "ioredis-mock": "^5.5.5", "jest": "^26.6.3", - "pouchdb": "^7.2.1", "pouchdb-adapter-memory": "^7.2.2", "pouchdb-all-dbs": "^1.0.2" }, diff --git a/packages/backend-core/src/cache/appMetadata.js b/packages/backend-core/src/cache/appMetadata.js index 9e2317ae37..effdc886d7 100644 --- a/packages/backend-core/src/cache/appMetadata.js +++ b/packages/backend-core/src/cache/appMetadata.js @@ -1,5 +1,5 @@ const redis = require("../redis/authRedis") -const { getCouch } = require("../db") +const { doWithDB } = require("../db") const { DocumentTypes } = require("../db/constants") const AppState = { @@ -10,12 +10,14 @@ const EXPIRY_SECONDS = 3600 /** * The default populate app metadata function */ -const populateFromDB = async (appId, CouchDB = null) => { - if (!CouchDB) { - CouchDB = getCouch() - } - const db = new CouchDB(appId, { skip_setup: true }) - return db.get(DocumentTypes.APP_METADATA) +const populateFromDB = async appId => { + return doWithDB( + appId, + db => { + return db.get(DocumentTypes.APP_METADATA) + }, + { skip_setup: true } + ) } const isInvalid = metadata => { @@ -27,17 +29,16 @@ const isInvalid = metadata => { * Use redis cache to first read the app metadata. * If not present fallback to loading the app metadata directly and re-caching. * @param {string} appId the id of the app to get metadata from. - * @param {object} CouchDB the database being passed * @returns {object} the app metadata. */ -exports.getAppMetadata = async (appId, CouchDB = null) => { +exports.getAppMetadata = async appId => { const client = await redis.getAppClient() // try cache let metadata = await client.get(appId) if (!metadata) { let expiry = EXPIRY_SECONDS try { - metadata = await populateFromDB(appId, CouchDB) + metadata = await populateFromDB(appId) } catch (err) { // app DB left around, but no metadata, it is invalid if (err && err.status === 404) { diff --git a/packages/backend-core/src/cache/user.js b/packages/backend-core/src/cache/user.js index b10f854002..faac6de725 100644 --- a/packages/backend-core/src/cache/user.js +++ b/packages/backend-core/src/cache/user.js @@ -1,5 +1,5 @@ const redis = require("../redis/authRedis") -const { getTenantId, lookupTenantId, getGlobalDB } = require("../tenancy") +const { getTenantId, lookupTenantId, doWithGlobalDB } = require("../tenancy") const env = require("../environment") const accounts = require("../cloud/accounts") @@ -9,9 +9,8 @@ const EXPIRY_SECONDS = 3600 * The default populate user function */ const populateFromDB = async (userId, tenantId) => { - const user = await getGlobalDB(tenantId).get(userId) + const user = await doWithGlobalDB(tenantId, db => db.get(userId)) user.budibaseAccess = true - if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { const account = await accounts.getAccount(user.email) if (account) { diff --git a/packages/backend-core/src/cloud/api.js b/packages/backend-core/src/cloud/api.js index ffa785d02a..d4d4b6c8bb 100644 --- a/packages/backend-core/src/cloud/api.js +++ b/packages/backend-core/src/cloud/api.js @@ -29,9 +29,7 @@ class API { credentials: "include", } - const resp = await fetch(`${this.host}${url}`, requestOptions) - - return resp + return await fetch(`${this.host}${url}`, requestOptions) } post = this.apiCall("POST") diff --git a/packages/backend-core/src/context/FunctionContext.js b/packages/backend-core/src/context/FunctionContext.js index 1a3f65056e..34d39492f9 100644 --- a/packages/backend-core/src/context/FunctionContext.js +++ b/packages/backend-core/src/context/FunctionContext.js @@ -4,7 +4,11 @@ const { newid } = require("../hashing") const REQUEST_ID_KEY = "requestId" class FunctionContext { - static getMiddleware(updateCtxFn = null, contextName = "session") { + static getMiddleware( + updateCtxFn = null, + destroyFn = null, + contextName = "session" + ) { const namespace = this.createNamespace(contextName) return async function (ctx, next) { @@ -18,7 +22,14 @@ class FunctionContext { if (updateCtxFn) { updateCtxFn(ctx) } - next().then(resolve).catch(reject) + next() + .then(resolve) + .catch(reject) + .finally(() => { + if (destroyFn) { + return destroyFn(ctx) + } + }) }) ) } diff --git a/packages/backend-core/src/context/deprovision.js b/packages/backend-core/src/context/deprovision.js index 9f89dbbfa9..ba3c2d8449 100644 --- a/packages/backend-core/src/context/deprovision.js +++ b/packages/backend-core/src/context/deprovision.js @@ -1,6 +1,6 @@ const { getGlobalUserParams, getAllApps } = require("../db/utils") -const { getDB } = require("../db") -const { getGlobalDB } = require("../tenancy") +const { doWithDB } = require("../db") +const { doWithGlobalDB } = require("../tenancy") const { StaticDatabases } = require("../db/constants") const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants @@ -8,11 +8,12 @@ const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name const removeTenantFromInfoDB = async tenantId => { try { - const infoDb = getDB(PLATFORM_INFO_DB) - let tenants = await infoDb.get(TENANT_DOC) - tenants.tenantIds = tenants.tenantIds.filter(id => id !== tenantId) + await doWithDB(PLATFORM_INFO_DB, async infoDb => { + let tenants = await infoDb.get(TENANT_DOC) + tenants.tenantIds = tenants.tenantIds.filter(id => id !== tenantId) - await infoDb.put(tenants) + await infoDb.put(tenants) + }) } catch (err) { console.error(`Error removing tenant ${tenantId} from info db`, err) throw err @@ -20,36 +21,8 @@ const removeTenantFromInfoDB = async tenantId => { } exports.removeUserFromInfoDB = async dbUser => { - const infoDb = getDB(PLATFORM_INFO_DB) - const keys = [dbUser._id, dbUser.email] - const userDocs = await infoDb.allDocs({ - keys, - include_docs: true, - }) - const toDelete = userDocs.rows.map(row => { - return { - ...row.doc, - _deleted: true, - } - }) - await infoDb.bulkDocs(toDelete) -} - -const removeUsersFromInfoDB = async tenantId => { - try { - const globalDb = getGlobalDB(tenantId) - const infoDb = getDB(PLATFORM_INFO_DB) - const allUsers = await globalDb.allDocs( - getGlobalUserParams(null, { - include_docs: true, - }) - ) - const allEmails = allUsers.rows.map(row => row.doc.email) - // get the id docs - let keys = allUsers.rows.map(row => row.id) - // and the email docs - keys = keys.concat(allEmails) - // retrieve the docs and delete them + await doWithDB(PLATFORM_INFO_DB, async infoDb => { + const keys = [dbUser._id, dbUser.email] const userDocs = await infoDb.allDocs({ keys, include_docs: true, @@ -61,26 +34,60 @@ const removeUsersFromInfoDB = async tenantId => { } }) await infoDb.bulkDocs(toDelete) - } catch (err) { - console.error(`Error removing tenant ${tenantId} users from info db`, err) - throw err - } + }) +} + +const removeUsersFromInfoDB = async tenantId => { + return doWithGlobalDB(tenantId, async db => { + try { + const allUsers = await db.allDocs( + getGlobalUserParams(null, { + include_docs: true, + }) + ) + await doWithDB(PLATFORM_INFO_DB, async infoDb => { + const allEmails = allUsers.rows.map(row => row.doc.email) + // get the id docs + let keys = allUsers.rows.map(row => row.id) + // and the email docs + keys = keys.concat(allEmails) + // retrieve the docs and delete them + const userDocs = await infoDb.allDocs({ + keys, + include_docs: true, + }) + const toDelete = userDocs.rows.map(row => { + return { + ...row.doc, + _deleted: true, + } + }) + await infoDb.bulkDocs(toDelete) + }) + } catch (err) { + console.error(`Error removing tenant ${tenantId} users from info db`, err) + throw err + } + }) } const removeGlobalDB = async tenantId => { - try { - const globalDb = getGlobalDB(tenantId) - await globalDb.destroy() - } catch (err) { - console.error(`Error removing tenant ${tenantId} users from info db`, err) - throw err - } + return doWithGlobalDB(tenantId, async db => { + try { + await db.destroy() + } catch (err) { + console.error(`Error removing tenant ${tenantId} users from info db`, err) + throw err + } + }) } const removeTenantApps = async tenantId => { try { const apps = await getAllApps({ all: true }) - const destroyPromises = apps.map(app => getDB(app.appId).destroy()) + const destroyPromises = apps.map(app => + doWithDB(app.appId, db => db.destroy()) + ) await Promise.allSettled(destroyPromises) } catch (err) { console.error(`Error removing tenant ${tenantId} apps`, err) diff --git a/packages/backend-core/src/context/index.js b/packages/backend-core/src/context/index.js index 59c3dc9e16..acf8434d3b 100644 --- a/packages/backend-core/src/context/index.js +++ b/packages/backend-core/src/context/index.js @@ -1,9 +1,11 @@ const env = require("../environment") const { Headers } = require("../../constants") const { SEPARATOR, DocumentTypes } = require("../db/constants") +const { DEFAULT_TENANT_ID } = require("../constants") const cls = require("./FunctionContext") -const { getCouch } = require("../db") +const { dangerousGetDB, closeDB } = require("../db") const { getProdAppID, getDevelopmentAppID } = require("../db/conversions") +const { baseGlobalDBName } = require("../tenancy/utils") const { isEqual } = require("lodash") // some test cases call functions directly, need to @@ -12,6 +14,7 @@ let TEST_APP_ID = null const ContextKeys = { TENANT_ID: "tenantId", + GLOBAL_DB: "globalDb", APP_ID: "appId", // whatever the request app DB was CURRENT_DB: "currentDb", @@ -20,9 +23,37 @@ const ContextKeys = { // get the dev app DB from the request DEV_DB: "devDb", DB_OPTS: "dbOpts", + // check if something else is using the context, don't close DB + IN_USE: "inUse", } -exports.DEFAULT_TENANT_ID = "default" +exports.DEFAULT_TENANT_ID = DEFAULT_TENANT_ID + +// this function makes sure the PouchDB objects are closed and +// fully deleted when finished - this protects against memory leaks +async function closeAppDBs() { + const dbKeys = [ + ContextKeys.CURRENT_DB, + ContextKeys.PROD_DB, + ContextKeys.DEV_DB, + ] + for (let dbKey of dbKeys) { + const db = cls.getFromContext(dbKey) + if (!db) { + continue + } + await closeDB(db) + // clear the DB from context, incase someone tries to use it again + cls.setOnContext(dbKey, null) + } + // clear the app ID now that the databases are closed + if (cls.getFromContext(ContextKeys.APP_ID)) { + cls.setOnContext(ContextKeys.APP_ID, null) + } + if (cls.getFromContext(ContextKeys.DB_OPTS)) { + cls.setOnContext(ContextKeys.DB_OPTS, null) + } +} exports.isDefaultTenant = () => { return exports.getTenantId() === exports.DEFAULT_TENANT_ID @@ -34,13 +65,40 @@ exports.isMultiTenant = () => { // used for automations, API endpoints should always be in context already exports.doInTenant = (tenantId, task) => { - return cls.run(() => { + // the internal function is so that we can re-use an existing + // context - don't want to close DB on a parent context + async function internal(opts = { existing: false }) { // set the tenant id - cls.setOnContext(ContextKeys.TENANT_ID, tenantId) + if (!opts.existing) { + cls.setOnContext(ContextKeys.TENANT_ID, tenantId) + exports.setGlobalDB(tenantId) + } - // invoke the task - return task() - }) + try { + // invoke the task + return await task() + } finally { + const using = cls.getFromContext(ContextKeys.IN_USE) + if (!using || using <= 1) { + await closeDB(exports.getGlobalDB()) + // clear from context now that database is closed/task is finished + cls.setOnContext(ContextKeys.TENANT_ID, null) + cls.setOnContext(ContextKeys.GLOBAL_DB, null) + } else { + cls.setOnContext(using - 1) + } + } + } + const using = cls.getFromContext(ContextKeys.IN_USE) + if (using && cls.getFromContext(ContextKeys.TENANT_ID) === tenantId) { + cls.setOnContext(ContextKeys.IN_USE, using + 1) + return internal({ existing: true }) + } else { + return cls.run(async () => { + cls.setOnContext(ContextKeys.IN_USE, 1) + return internal() + }) + } } /** @@ -64,37 +122,58 @@ exports.getTenantIDFromAppID = appId => { } const setAppTenantId = appId => { - const appTenantId = this.getTenantIDFromAppID(appId) || this.DEFAULT_TENANT_ID - this.updateTenantId(appTenantId) + const appTenantId = + exports.getTenantIDFromAppID(appId) || exports.DEFAULT_TENANT_ID + exports.updateTenantId(appTenantId) } exports.doInAppContext = (appId, task) => { if (!appId) { throw new Error("appId is required") } - return cls.run(() => { - // set the app tenant id - setAppTenantId(appId) + // the internal function is so that we can re-use an existing + // context - don't want to close DB on a parent context + async function internal(opts = { existing: false }) { + // set the app tenant id + if (!opts.existing) { + setAppTenantId(appId) + } // set the app ID cls.setOnContext(ContextKeys.APP_ID, appId) - - // invoke the task - return task() - }) + try { + // invoke the task + return await task() + } finally { + const using = cls.getFromContext(ContextKeys.IN_USE) + if (!using || using <= 1) { + await closeAppDBs() + } else { + cls.setOnContext(using - 1) + } + } + } + const using = cls.getFromContext(ContextKeys.IN_USE) + if (using && cls.getFromContext(ContextKeys.APP_ID) === appId) { + cls.setOnContext(ContextKeys.IN_USE, using + 1) + return internal({ existing: true }) + } else { + return cls.run(async () => { + cls.setOnContext(ContextKeys.IN_USE, 1) + return internal() + }) + } } exports.updateTenantId = tenantId => { cls.setOnContext(ContextKeys.TENANT_ID, tenantId) } -exports.updateAppId = appId => { +exports.updateAppId = async appId => { try { + // have to close first, before removing the databases from context + await closeAppDBs() cls.setOnContext(ContextKeys.APP_ID, appId) - cls.setOnContext(ContextKeys.PROD_DB, null) - cls.setOnContext(ContextKeys.DEV_DB, null) - cls.setOnContext(ContextKeys.CURRENT_DB, null) - cls.setOnContext(ContextKeys.DB_OPTS, null) } catch (err) { if (env.isTest()) { TEST_APP_ID = appId @@ -111,8 +190,8 @@ exports.setTenantId = ( let tenantId // exit early if not multi-tenant if (!exports.isMultiTenant()) { - cls.setOnContext(ContextKeys.TENANT_ID, this.DEFAULT_TENANT_ID) - return + cls.setOnContext(ContextKeys.TENANT_ID, exports.DEFAULT_TENANT_ID) + return exports.DEFAULT_TENANT_ID } const allowQs = opts && opts.allowQs @@ -140,6 +219,22 @@ exports.setTenantId = ( if (tenantId) { cls.setOnContext(ContextKeys.TENANT_ID, tenantId) } + return tenantId +} + +exports.setGlobalDB = tenantId => { + const dbName = baseGlobalDBName(tenantId) + const db = dangerousGetDB(dbName) + cls.setOnContext(ContextKeys.GLOBAL_DB, db) + return db +} + +exports.getGlobalDB = () => { + const db = cls.getFromContext(ContextKeys.GLOBAL_DB) + if (!db) { + throw new Error("Global DB not found") + } + return db } exports.isTenantIdSet = () => { @@ -167,7 +262,7 @@ exports.getAppId = () => { } } -function getDB(key, opts) { +function getContextDB(key, opts) { const dbOptsKey = `${key}${ContextKeys.DB_OPTS}` let storedOpts = cls.getFromContext(dbOptsKey) let db = cls.getFromContext(key) @@ -176,7 +271,6 @@ function getDB(key, opts) { } const appId = exports.getAppId() - const CouchDB = getCouch() let toUseAppId switch (key) { @@ -190,7 +284,7 @@ function getDB(key, opts) { toUseAppId = getDevelopmentAppID(appId) break } - db = new CouchDB(toUseAppId, opts) + db = dangerousGetDB(toUseAppId, opts) try { cls.setOnContext(key, db) if (opts) { @@ -209,7 +303,7 @@ function getDB(key, opts) { * contained, dev or prod. */ exports.getAppDB = opts => { - return getDB(ContextKeys.CURRENT_DB, opts) + return getContextDB(ContextKeys.CURRENT_DB, opts) } /** @@ -217,7 +311,7 @@ exports.getAppDB = opts => { * contained a development app ID, this will open the prod one. */ exports.getProdAppDB = opts => { - return getDB(ContextKeys.PROD_DB, opts) + return getContextDB(ContextKeys.PROD_DB, opts) } /** @@ -225,5 +319,5 @@ exports.getProdAppDB = opts => { * contained a prod app ID, this will open the dev one. */ exports.getDevAppDB = opts => { - return getDB(ContextKeys.DEV_DB, opts) + return getContextDB(ContextKeys.DEV_DB, opts) } diff --git a/packages/backend-core/src/db/Replication.js b/packages/backend-core/src/db/Replication.js index 7af3c2eb9d..437d07e536 100644 --- a/packages/backend-core/src/db/Replication.js +++ b/packages/backend-core/src/db/Replication.js @@ -1,4 +1,4 @@ -const { getDB } = require(".") +const { dangerousGetDB, closeDB } = require(".") class Replication { /** @@ -7,8 +7,12 @@ class Replication { * @param {String} target - the DB you want to replicate to, or rollback from */ constructor({ source, target }) { - this.source = getDB(source) - this.target = getDB(target) + this.source = dangerousGetDB(source) + this.target = dangerousGetDB(target) + } + + close() { + return Promise.all([closeDB(this.source), closeDB(this.target)]) } promisify(operation, opts = {}) { @@ -51,7 +55,7 @@ class Replication { async rollback() { await this.target.destroy() // Recreate the DB again - this.target = getDB(this.target.name) + this.target = dangerousGetDB(this.target.name) await this.replicate() } diff --git a/packages/backend-core/src/db/index.js b/packages/backend-core/src/db/index.js index 163364dbf3..1a29c8c2b0 100644 --- a/packages/backend-core/src/db/index.js +++ b/packages/backend-core/src/db/index.js @@ -1,13 +1,67 @@ -let Pouch +const pouch = require("./pouch") +const env = require("../environment") -module.exports.setDB = pouch => { - Pouch = pouch +let PouchDB +let initialised = false + +const put = + dbPut => + async (doc, options = {}) => { + const response = await dbPut(doc, options) + // TODO: add created / updated + return response + } + +const checkInitialised = () => { + if (!initialised) { + throw new Error("init has not been called") + } } -module.exports.getDB = dbName => { - return new Pouch(dbName) +exports.init = opts => { + PouchDB = pouch.getPouch(opts) + initialised = true } -module.exports.getCouch = () => { - return Pouch +// NOTE: THIS IS A DANGEROUS FUNCTION - USE WITH CAUTION +// this function is prone to leaks, should only be used +// in situations that using the function doWithDB does not work +exports.dangerousGetDB = (dbName, opts) => { + checkInitialised() + const db = new PouchDB(dbName, opts) + const dbPut = db.put + db.put = put(dbPut) + return db +} + +// use this function if you have called dangerousGetDB - close +// the databases you've opened once finished +exports.closeDB = async db => { + if (!db || env.isTest()) { + return + } + try { + return db.close() + } catch (err) { + // ignore error, already closed + } +} + +// we have to use a callback for this so that we can close +// the DB when we're done, without this manual requests would +// need to close the database when done with it to avoid memory leaks +exports.doWithDB = async (dbName, cb, opts) => { + const db = exports.dangerousGetDB(dbName, opts) + // need this to be async so that we can correctly close DB after all + // async operations have been completed + try { + return await cb(db) + } finally { + await exports.closeDB(db) + } +} + +exports.allDbs = () => { + checkInitialised() + return PouchDB.allDbs() } diff --git a/packages/backend-core/src/db/pouch.js b/packages/backend-core/src/db/pouch.js new file mode 100644 index 0000000000..722913aa67 --- /dev/null +++ b/packages/backend-core/src/db/pouch.js @@ -0,0 +1,93 @@ +const PouchDB = require("pouchdb") +const env = require("../environment") + +exports.getCouchUrl = () => { + if (!env.COUCH_DB_URL) return + + // username and password already exist in URL + if (env.COUCH_DB_URL.includes("@")) { + return env.COUCH_DB_URL + } + + const [protocol, ...rest] = env.COUCH_DB_URL.split("://") + + if (!env.COUCH_DB_USERNAME || !env.COUCH_DB_PASSWORD) { + throw new Error( + "CouchDB configuration invalid. You must provide a fully qualified CouchDB url, or the COUCH_DB_USER and COUCH_DB_PASSWORD environment variables." + ) + } + + return `${protocol}://${env.COUCH_DB_USERNAME}:${env.COUCH_DB_PASSWORD}@${rest}` +} + +exports.splitCouchUrl = url => { + const [protocol, rest] = url.split("://") + const [auth, host] = rest.split("@") + const [username, password] = auth.split(":") + return { + url: `${protocol}://${host}`, + auth: { + username, + password, + }, + } +} + +/** + * Return a constructor for PouchDB. + * This should be rarely used outside of the main application config. + * Exposed for exceptional cases such as in-memory views. + */ +exports.getPouch = (opts = {}) => { + let auth = { + username: env.COUCH_DB_USERNAME, + password: env.COUCH_DB_PASSWORD, + } + let url = exports.getCouchUrl() || "http://localhost:4005" + // need to update security settings + if (!auth.username || !auth.password || url.includes("@")) { + const split = exports.splitCouchUrl(url) + url = split.url + auth = split.auth + } + + const authCookie = Buffer.from(`${auth.username}:${auth.password}`).toString( + "base64" + ) + let POUCH_DB_DEFAULTS = { + prefix: url, + fetch: (url, opts) => { + // use a specific authorization cookie - be very explicit about how we authenticate + opts.headers.set("Authorization", `Basic ${authCookie}`) + return PouchDB.fetch(url, opts) + }, + } + + if (opts.inMemory) { + const inMemory = require("pouchdb-adapter-memory") + PouchDB.plugin(inMemory) + POUCH_DB_DEFAULTS = { + prefix: undefined, + adapter: "memory", + } + } + + if (opts.replication) { + const replicationStream = require("pouchdb-replication-stream") + PouchDB.plugin(replicationStream.plugin) + PouchDB.adapter("writableStream", replicationStream.adapters.writableStream) + } + + if (opts.find) { + const find = require("pouchdb-find") + PouchDB.plugin(find) + } + + const Pouch = PouchDB.defaults(POUCH_DB_DEFAULTS) + if (opts.allDbs) { + const allDbs = require("pouchdb-all-dbs") + allDbs(Pouch) + } + + return Pouch +} diff --git a/packages/backend-core/src/db/utils.js b/packages/backend-core/src/db/utils.js index ac401dea85..9e2a06d065 100644 --- a/packages/backend-core/src/db/utils.js +++ b/packages/backend-core/src/db/utils.js @@ -11,7 +11,8 @@ const { } = require("./constants") const { getTenantId, getGlobalDBName } = require("../tenancy") const fetch = require("node-fetch") -const { getCouch } = require("./index") +const { doWithDB, allDbs } = require("./index") +const { getCouchUrl } = require("./pouch") const { getAppMetadata } = require("../cache/appMetadata") const { checkSlashesInUrl } = require("../helpers") const { @@ -150,25 +151,6 @@ exports.getRoleParams = (roleId = null, otherProps = {}) => { return getDocParams(DocumentTypes.ROLE, roleId, otherProps) } -exports.getCouchUrl = () => { - if (!env.COUCH_DB_URL) return - - // username and password already exist in URL - if (env.COUCH_DB_URL.includes("@")) { - return env.COUCH_DB_URL - } - - const [protocol, ...rest] = env.COUCH_DB_URL.split("://") - - if (!env.COUCH_DB_USERNAME || !env.COUCH_DB_PASSWORD) { - throw new Error( - "CouchDB configuration invalid. You must provide a fully qualified CouchDB url, or the COUCH_DB_USER and COUCH_DB_PASSWORD environment variables." - ) - } - - return `${protocol}://${env.COUCH_DB_USERNAME}:${env.COUCH_DB_PASSWORD}@${rest}` -} - exports.getStartEndKeyURL = (base, baseKey, tenantId = null) => { const tenancy = tenantId ? `${SEPARATOR}${tenantId}` : "" return `${base}?startkey="${baseKey}${tenancy}"&endkey="${baseKey}${tenancy}${UNICODE_MAX}"` @@ -184,7 +166,7 @@ exports.getAllDbs = async (opts = { efficient: false }) => { const efficient = opts && opts.efficient // specifically for testing we use the pouch package for this if (env.isTest()) { - return getCouch().allDbs() + return allDbs() } let dbs = [] async function addDbs(url) { @@ -196,7 +178,7 @@ exports.getAllDbs = async (opts = { efficient: false }) => { throw "Cannot connect to CouchDB instance" } } - let couchUrl = `${exports.getCouchUrl()}/_all_dbs` + let couchUrl = `${getCouchUrl()}/_all_dbs` let tenantId = getTenantId() if (!env.MULTI_TENANCY || (!efficient && tenantId === DEFAULT_TENANT_ID)) { // just get all DBs when: @@ -227,7 +209,6 @@ exports.getAllDbs = async (opts = { efficient: false }) => { * @return {Promise} returns the app information document stored in each app database. */ exports.getAllApps = async ({ dev, all, idsOnly, efficient } = {}) => { - const CouchDB = getCouch() let tenantId = getTenantId() if (!env.MULTI_TENANCY && !tenantId) { tenantId = DEFAULT_TENANT_ID @@ -255,7 +236,7 @@ exports.getAllApps = async ({ dev, all, idsOnly, efficient } = {}) => { } const appPromises = appDbNames.map(app => // skip setup otherwise databases could be re-created - getAppMetadata(app, CouchDB) + getAppMetadata(app) ) if (appPromises.length === 0) { return [] @@ -299,19 +280,23 @@ exports.getDevAppIDs = async () => { } exports.dbExists = async dbName => { - const CouchDB = getCouch() let exists = false - try { - const db = CouchDB(dbName, { skip_setup: true }) - // check if database exists - const info = await db.info() - if (info && !info.error) { - exists = true - } - } catch (err) { - exists = false - } - return exists + return doWithDB( + dbName, + async db => { + try { + // check if database exists + const info = await db.info() + if (info && !info.error) { + exists = true + } + } catch (err) { + exists = false + } + return exists + }, + { skip_setup: true } + ) } /** @@ -436,3 +421,4 @@ exports.generateConfigID = generateConfigID exports.getConfigParams = getConfigParams exports.getScopedFullConfig = getScopedFullConfig exports.generateDevInfoID = generateDevInfoID +exports.getPlatformUrl = getPlatformUrl diff --git a/packages/backend-core/src/index.js b/packages/backend-core/src/index.js index 8f71580162..3868d9bffa 100644 --- a/packages/backend-core/src/index.js +++ b/packages/backend-core/src/index.js @@ -1,8 +1,8 @@ -const { setDB } = require("./db") +const db = require("./db") module.exports = { - init(pouch) { - setDB(pouch) + init(opts = {}) { + db.init(opts.db) }, // some default exports from the library, however these ideally shouldn't // be used, instead the syntax require("@budibase/backend-core/db") should be used diff --git a/packages/backend-core/src/middleware/passport/datasource/google.js b/packages/backend-core/src/middleware/passport/datasource/google.js index 5046815b1f..96c7f99953 100644 --- a/packages/backend-core/src/middleware/passport/datasource/google.js +++ b/packages/backend-core/src/middleware/passport/datasource/google.js @@ -1,8 +1,8 @@ const google = require("../google") const { Cookies, Configs } = require("../../../constants") const { clearCookie, getCookie } = require("../../../utils") -const { getDB } = require("../../../db") -const { getScopedConfig } = require("../../../db/utils") +const { getScopedConfig, getPlatformUrl } = require("../../../db/utils") +const { doWithDB } = require("../../../db") const environment = require("../../../environment") const { getGlobalDB } = require("../../../tenancy") @@ -13,18 +13,28 @@ async function fetchGoogleCreds() { type: Configs.GOOGLE, }) // or fall back to env variables - const config = googleConfig || { - clientID: environment.GOOGLE_CLIENT_ID, - clientSecret: environment.GOOGLE_CLIENT_SECRET, - } + return ( + googleConfig || { + clientID: environment.GOOGLE_CLIENT_ID, + clientSecret: environment.GOOGLE_CLIENT_SECRET, + } + ) +} - return config +async function platformUrl() { + const db = getGlobalDB() + const publicConfig = await getScopedConfig(db, { + type: Configs.SETTINGS, + }) + return getPlatformUrl(publicConfig) } async function preAuth(passport, ctx, next) { // get the relevant config const googleConfig = await fetchGoogleCreds() - let callbackUrl = `${environment.PLATFORM_URL}/api/global/auth/datasource/google/callback` + const platUrl = await platformUrl() + + let callbackUrl = `${platUrl}/api/global/auth/datasource/google/callback` const strategy = await google.strategyFactory(googleConfig, callbackUrl) if (!ctx.query.appId || !ctx.query.datasourceId) { @@ -41,14 +51,15 @@ async function preAuth(passport, ctx, next) { async function postAuth(passport, ctx, next) { // get the relevant config const config = await fetchGoogleCreds() + const platUrl = await platformUrl() - let callbackUrl = `${environment.PLATFORM_URL}/api/global/auth/datasource/google/callback` + let callbackUrl = `${platUrl}/api/global/auth/datasource/google/callback` const strategy = await google.strategyFactory( config, callbackUrl, (accessToken, refreshToken, profile, done) => { clearCookie(ctx, Cookies.DatasourceAuth) - done(null, { accessToken, refreshToken }) + done(null, { refreshToken }) } ) @@ -59,16 +70,17 @@ async function postAuth(passport, ctx, next) { { successRedirect: "/", failureRedirect: "/error" }, async (err, tokens) => { // update the DB for the datasource with all the user info - const db = getDB(authStateCookie.appId) - const datasource = await db.get(authStateCookie.datasourceId) - if (!datasource.config) { - datasource.config = {} - } - datasource.config.auth = { type: "google", ...tokens } - await db.put(datasource) - ctx.redirect( - `/builder/app/${authStateCookie.appId}/data/datasource/${authStateCookie.datasourceId}` - ) + await doWithDB(authStateCookie.appId, async db => { + const datasource = await db.get(authStateCookie.datasourceId) + if (!datasource.config) { + datasource.config = {} + } + datasource.config.auth = { type: "google", ...tokens } + await db.put(datasource) + ctx.redirect( + `/builder/app/${authStateCookie.appId}/data/datasource/${authStateCookie.datasourceId}` + ) + }) } )(ctx, next) } diff --git a/packages/backend-core/src/middleware/passport/tests/third-party-common.spec.js b/packages/backend-core/src/middleware/passport/tests/third-party-common.spec.js index 3a3c55bfa0..2a1c4b6360 100644 --- a/packages/backend-core/src/middleware/passport/tests/third-party-common.spec.js +++ b/packages/backend-core/src/middleware/passport/tests/third-party-common.spec.js @@ -2,17 +2,13 @@ require("../../../tests/utilities/dbConfig") -const database = require("../../../db") const { authenticateThirdParty } = require("../third-party-common") const { data } = require("./utilities/mock-data") +const { DEFAULT_TENANT_ID } = require("../../../constants") -const { - StaticDatabases, - generateGlobalUserID -} = require("../../../db/utils") +const { generateGlobalUserID } = require("../../../db/utils") const { newid } = require("../../../hashing") - -let db +const { doWithGlobalDB, doInTenant } = require("../../../tenancy") const done = jest.fn() @@ -21,43 +17,52 @@ const getErrorMessage = () => { } const saveUser = async (user) => { - return await db.put(user) + return doWithGlobalDB(DEFAULT_TENANT_ID, async db => { + return await db.put(user) + }) +} + +function authenticate(user, requireLocal, saveFn) { + return doInTenant(DEFAULT_TENANT_ID, () => { + return authenticateThirdParty(user, requireLocal, done, saveFn) + }) } describe("third party common", () => { - describe("authenticateThirdParty", () => { + describe("authenticateThirdParty", () => { let thirdPartyUser - + beforeEach(() => { - db = database.getDB(StaticDatabases.GLOBAL.name) thirdPartyUser = data.buildThirdPartyUser() }) afterEach(async () => { - jest.clearAllMocks() - await db.destroy() + return doWithGlobalDB(DEFAULT_TENANT_ID, async db => { + jest.clearAllMocks() + await db.destroy() + }) }) - + describe("validation", () => { const testValidation = async (message) => { - await authenticateThirdParty(thirdPartyUser, false, done, saveUser) + await authenticate(thirdPartyUser, false, saveUser) expect(done.mock.calls.length).toBe(1) expect(getErrorMessage()).toContain(message) } it("provider fails", async () => { delete thirdPartyUser.provider - testValidation("third party user provider required") + await testValidation("third party user provider required") }) it("user id fails", async () => { delete thirdPartyUser.userId - testValidation("third party user id required") + await testValidation("third party user id required") }) it("email fails", async () => { delete thirdPartyUser.email - testValidation("third party user email required") + await testValidation("third party user email required") }) }) @@ -81,34 +86,37 @@ describe("third party common", () => { describe("when the user doesn't exist", () => { describe("when a local account is required", () => { it("returns an error message", async () => { - await authenticateThirdParty(thirdPartyUser, true, done, saveUser) + await authenticate(thirdPartyUser, true, saveUser) expect(done.mock.calls.length).toBe(1) expect(getErrorMessage()).toContain("Email does not yet exist. You must set up your local budibase account first.") }) }) - + describe("when a local account isn't required", () => { it("creates and authenticates the user", async () => { - await authenticateThirdParty(thirdPartyUser, false, done, saveUser) + await authenticate(thirdPartyUser, false, saveUser) const user = expectUserIsAuthenticated() expectUserIsSynced(user, thirdPartyUser) expect(user.roles).toStrictEqual({}) }) }) }) - + describe("when the user exists", () => { let dbUser let id let email const createUser = async () => { - dbUser = { - _id: id, - email: email, - } - const response = await db.put(dbUser) - dbUser._rev = response.rev + return doWithGlobalDB(DEFAULT_TENANT_ID, async db => { + dbUser = { + _id: id, + email: email, + } + const response = await db.put(dbUser) + dbUser._rev = response.rev + return dbUser + }) } const expectUserIsUpdated = (user) => { @@ -126,8 +134,8 @@ describe("third party common", () => { }) it("syncs and authenticates the user", async () => { - await authenticateThirdParty(thirdPartyUser, true, done, saveUser) - + await authenticate(thirdPartyUser, true, saveUser) + const user = expectUserIsAuthenticated() expectUserIsSynced(user, thirdPartyUser) expectUserIsUpdated(user) @@ -142,8 +150,8 @@ describe("third party common", () => { }) it("syncs and authenticates the user", async () => { - await authenticateThirdParty(thirdPartyUser, true, done, saveUser) - + await authenticate(thirdPartyUser, true, saveUser) + const user = expectUserIsAuthenticated() expectUserIsSynced(user, thirdPartyUser) expectUserIsUpdated(user) @@ -160,8 +168,8 @@ describe("third party common", () => { }) it("syncs and authenticates the user", async () => { - await authenticateThirdParty(thirdPartyUser, true, done, saveUser) - + await authenticate(thirdPartyUser, true, saveUser) + const user = expectUserIsAuthenticated() expectUserIsSynced(user, thirdPartyUser) expectUserIsUpdated(user) diff --git a/packages/backend-core/src/middleware/tenancy.js b/packages/backend-core/src/middleware/tenancy.js index 5bb81f8824..f4053d1f5b 100644 --- a/packages/backend-core/src/middleware/tenancy.js +++ b/packages/backend-core/src/middleware/tenancy.js @@ -1,4 +1,5 @@ -const { setTenantId } = require("../tenancy") +const { setTenantId, setGlobalDB, getGlobalDB } = require("../tenancy") +const { closeDB } = require("../db") const ContextFactory = require("../context/FunctionContext") const { buildMatcherRegex, matches } = require("./matchers") @@ -10,10 +11,17 @@ module.exports = ( const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns) const noTenancyOptions = buildMatcherRegex(noTenancyPatterns) - return ContextFactory.getMiddleware(ctx => { + const updateCtxFn = ctx => { const allowNoTenant = opts.noTenancyRequired || !!matches(ctx, noTenancyOptions) const allowQs = !!matches(ctx, allowQsOptions) - setTenantId(ctx, { allowQs, allowNoTenant }) - }) + const tenantId = setTenantId(ctx, { allowQs, allowNoTenant }) + setGlobalDB(tenantId) + } + const destroyFn = async () => { + const db = getGlobalDB() + await closeDB(db) + } + + return ContextFactory.getMiddleware(updateCtxFn, destroyFn) } diff --git a/packages/backend-core/src/migrations/index.js b/packages/backend-core/src/migrations/index.js index db0fe6b8ce..ada1478ace 100644 --- a/packages/backend-core/src/migrations/index.js +++ b/packages/backend-core/src/migrations/index.js @@ -1,4 +1,5 @@ const { DEFAULT_TENANT_ID } = require("../constants") +const { doWithDB } = require("../db") const { DocumentTypes } = require("../db/constants") const { getAllApps } = require("../db/utils") const environment = require("../environment") @@ -26,7 +27,7 @@ exports.getMigrationsDoc = async db => { } } -const runMigration = async (CouchDB, migration, options = {}) => { +const runMigration = async (migration, options = {}) => { const tenantId = getTenantId() const migrationType = migration.type const migrationName = migration.name @@ -46,49 +47,50 @@ const runMigration = async (CouchDB, migration, options = {}) => { // run the migration against each db for (const dbName of dbNames) { - const db = new CouchDB(dbName) - try { - const doc = await exports.getMigrationsDoc(db) + await doWithDB(dbName, async db => { + try { + const doc = await exports.getMigrationsDoc(db) - // exit if the migration has been performed already - if (doc[migrationName]) { - if ( - options.force && - options.force[migrationType] && - options.force[migrationType].includes(migrationName) - ) { - console.log( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Forcing` - ) - } else { - // the migration has already been performed - continue + // exit if the migration has been performed already + if (doc[migrationName]) { + if ( + options.force && + options.force[migrationType] && + options.force[migrationType].includes(migrationName) + ) { + console.log( + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Forcing` + ) + } else { + // the migration has already been performed + return + } } + + console.log( + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Running` + ) + // run the migration with tenant context + await migration.fn(db) + console.log( + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Complete` + ) + + // mark as complete + doc[migrationName] = Date.now() + await db.put(doc) + } catch (err) { + console.error( + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Error: `, + err + ) + throw err } - - console.log( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Running` - ) - // run the migration with tenant context - await migration.fn(db) - console.log( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Complete` - ) - - // mark as complete - doc[migrationName] = Date.now() - await db.put(doc) - } catch (err) { - console.error( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Error: `, - err - ) - throw err - } + }) } } -exports.runMigrations = async (CouchDB, migrations, options = {}) => { +exports.runMigrations = async (migrations, options = {}) => { console.log("Running migrations") let tenantIds if (environment.MULTI_TENANCY) { @@ -108,9 +110,7 @@ exports.runMigrations = async (CouchDB, migrations, options = {}) => { // for all migrations for (const migration of migrations) { // run the migration - await doInTenant(tenantId, () => - runMigration(CouchDB, migration, options) - ) + await doInTenant(tenantId, () => runMigration(migration, options)) } } console.log("Migrations complete") diff --git a/packages/backend-core/src/migrations/tests/index.spec.js b/packages/backend-core/src/migrations/tests/index.spec.js index 12a2e54cb3..8d9cb4e4b5 100644 --- a/packages/backend-core/src/migrations/tests/index.spec.js +++ b/packages/backend-core/src/migrations/tests/index.spec.js @@ -1,7 +1,7 @@ require("../../tests/utilities/dbConfig") const { runMigrations, getMigrationsDoc } = require("../index") -const CouchDB = require("../../db").getCouch() +const { dangerousGetDB } = require("../../db") const { StaticDatabases, } = require("../../db/utils") @@ -20,7 +20,7 @@ describe("migrations", () => { }] beforeEach(() => { - db = new CouchDB(StaticDatabases.GLOBAL.name) + db = dangerousGetDB(StaticDatabases.GLOBAL.name) }) afterEach(async () => { @@ -29,7 +29,7 @@ describe("migrations", () => { }) const migrate = () => { - return runMigrations(CouchDB, MIGRATIONS) + return runMigrations(MIGRATIONS) } it("should run a new migration", async () => { diff --git a/packages/backend-core/src/security/roles.js b/packages/backend-core/src/security/roles.js index 8535cdc716..7c57cadcbf 100644 --- a/packages/backend-core/src/security/roles.js +++ b/packages/backend-core/src/security/roles.js @@ -7,7 +7,7 @@ const { SEPARATOR, } = require("../db/utils") const { getAppDB } = require("../context") -const { getDB } = require("../db") +const { doWithDB } = require("../db") const BUILTIN_IDS = { ADMIN: "ADMIN", @@ -199,43 +199,49 @@ exports.checkForRoleResourceArray = (rolePerms, resourceId) => { * @return {Promise} An array of the role objects that were found. */ exports.getAllRoles = async appId => { - const db = appId ? getDB(appId) : getAppDB() - const body = await db.allDocs( - getRoleParams(null, { - include_docs: true, - }) - ) - let roles = body.rows.map(row => row.doc) - const builtinRoles = exports.getBuiltinRoles() + if (appId) { + return doWithDB(appId, internal) + } else { + return internal(getAppDB()) + } + async function internal(db) { + const body = await db.allDocs( + getRoleParams(null, { + include_docs: true, + }) + ) + let roles = body.rows.map(row => row.doc) + const builtinRoles = exports.getBuiltinRoles() - // need to combine builtin with any DB record of them (for sake of permissions) - for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) { - const builtinRole = builtinRoles[builtinRoleId] - const dbBuiltin = roles.filter( - dbRole => exports.getExternalRoleID(dbRole._id) === builtinRoleId - )[0] - if (dbBuiltin == null) { - roles.push(builtinRole || builtinRoles.BASIC) - } else { - // remove role and all back after combining with the builtin - roles = roles.filter(role => role._id !== dbBuiltin._id) - dbBuiltin._id = exports.getExternalRoleID(dbBuiltin._id) - roles.push(Object.assign(builtinRole, dbBuiltin)) + // need to combine builtin with any DB record of them (for sake of permissions) + for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) { + const builtinRole = builtinRoles[builtinRoleId] + const dbBuiltin = roles.filter( + dbRole => exports.getExternalRoleID(dbRole._id) === builtinRoleId + )[0] + if (dbBuiltin == null) { + roles.push(builtinRole || builtinRoles.BASIC) + } else { + // remove role and all back after combining with the builtin + roles = roles.filter(role => role._id !== dbBuiltin._id) + dbBuiltin._id = exports.getExternalRoleID(dbBuiltin._id) + roles.push(Object.assign(builtinRole, dbBuiltin)) + } } + // check permissions + for (let role of roles) { + if (!role.permissions) { + continue + } + for (let resourceId of Object.keys(role.permissions)) { + role.permissions = exports.checkForRoleResourceArray( + role.permissions, + resourceId + ) + } + } + return roles } - // check permissions - for (let role of roles) { - if (!role.permissions) { - continue - } - for (let resourceId of Object.keys(role.permissions)) { - role.permissions = exports.checkForRoleResourceArray( - role.permissions, - resourceId - ) - } - } - return roles } /** diff --git a/packages/backend-core/src/tenancy/tenancy.js b/packages/backend-core/src/tenancy/tenancy.js index 24acc16862..b9d5ad7fbe 100644 --- a/packages/backend-core/src/tenancy/tenancy.js +++ b/packages/backend-core/src/tenancy/tenancy.js @@ -1,5 +1,6 @@ -const { getDB } = require("../db") -const { SEPARATOR, StaticDatabases } = require("../db/constants") +const { doWithDB } = require("../db") +const { StaticDatabases } = require("../db/constants") +const { baseGlobalDBName } = require("./utils") const { getTenantId, DEFAULT_TENANT_ID, @@ -23,59 +24,61 @@ exports.addTenantToUrl = url => { } exports.doesTenantExist = async tenantId => { - const db = getDB(PLATFORM_INFO_DB) - let tenants - try { - tenants = await db.get(TENANT_DOC) - } catch (err) { - // if theres an error the doc doesn't exist, no tenants exist - return false - } - return ( - tenants && - Array.isArray(tenants.tenantIds) && - tenants.tenantIds.indexOf(tenantId) !== -1 - ) + return doWithDB(PLATFORM_INFO_DB, async db => { + let tenants + try { + tenants = await db.get(TENANT_DOC) + } catch (err) { + // if theres an error the doc doesn't exist, no tenants exist + return false + } + return ( + tenants && + Array.isArray(tenants.tenantIds) && + tenants.tenantIds.indexOf(tenantId) !== -1 + ) + }) } exports.tryAddTenant = async (tenantId, userId, email) => { - const db = getDB(PLATFORM_INFO_DB) - const getDoc = async id => { - if (!id) { - return null + return doWithDB(PLATFORM_INFO_DB, async db => { + const getDoc = async id => { + if (!id) { + return null + } + try { + return await db.get(id) + } catch (err) { + return { _id: id } + } } - try { - return await db.get(id) - } catch (err) { - return { _id: id } + let [tenants, userIdDoc, emailDoc] = await Promise.all([ + getDoc(TENANT_DOC), + getDoc(userId), + getDoc(email), + ]) + if (!Array.isArray(tenants.tenantIds)) { + tenants = { + _id: TENANT_DOC, + tenantIds: [], + } } - } - let [tenants, userIdDoc, emailDoc] = await Promise.all([ - getDoc(TENANT_DOC), - getDoc(userId), - getDoc(email), - ]) - if (!Array.isArray(tenants.tenantIds)) { - tenants = { - _id: TENANT_DOC, - tenantIds: [], + let promises = [] + if (userIdDoc) { + userIdDoc.tenantId = tenantId + promises.push(db.put(userIdDoc)) } - } - let promises = [] - if (userIdDoc) { - userIdDoc.tenantId = tenantId - promises.push(db.put(userIdDoc)) - } - if (emailDoc) { - emailDoc.tenantId = tenantId - emailDoc.userId = userId - promises.push(db.put(emailDoc)) - } - if (tenants.tenantIds.indexOf(tenantId) === -1) { - tenants.tenantIds.push(tenantId) - promises.push(db.put(tenants)) - } - await Promise.all(promises) + if (emailDoc) { + emailDoc.tenantId = tenantId + emailDoc.userId = userId + promises.push(db.put(emailDoc)) + } + if (tenants.tenantIds.indexOf(tenantId) === -1) { + tenants.tenantIds.push(tenantId) + promises.push(db.put(tenants)) + } + await Promise.all(promises) + }) } exports.getGlobalDBName = (tenantId = null) => { @@ -84,43 +87,37 @@ exports.getGlobalDBName = (tenantId = null) => { if (!tenantId) { tenantId = getTenantId() } - - let dbName - if (tenantId === DEFAULT_TENANT_ID) { - dbName = StaticDatabases.GLOBAL.name - } else { - dbName = `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}` - } - return dbName + return baseGlobalDBName(tenantId) } -exports.getGlobalDB = (tenantId = null) => { - const dbName = exports.getGlobalDBName(tenantId) - return getDB(dbName) +exports.doWithGlobalDB = (tenantId, cb) => { + return doWithDB(exports.getGlobalDBName(tenantId), cb) } exports.lookupTenantId = async userId => { - const db = getDB(StaticDatabases.PLATFORM_INFO.name) - let tenantId = env.MULTI_TENANCY ? DEFAULT_TENANT_ID : null - try { - const doc = await db.get(userId) - if (doc && doc.tenantId) { - tenantId = doc.tenantId + return doWithDB(StaticDatabases.PLATFORM_INFO.name, async db => { + let tenantId = env.MULTI_TENANCY ? DEFAULT_TENANT_ID : null + try { + const doc = await db.get(userId) + if (doc && doc.tenantId) { + tenantId = doc.tenantId + } + } catch (err) { + // just return the default } - } catch (err) { - // just return the default - } - return tenantId + return tenantId + }) } // lookup, could be email or userId, either will return a doc exports.getTenantUser = async identifier => { - const db = getDB(PLATFORM_INFO_DB) - try { - return await db.get(identifier) - } catch (err) { - return null - } + return doWithDB(PLATFORM_INFO_DB, async db => { + try { + return await db.get(identifier) + } catch (err) { + return null + } + }) } exports.isUserInAppTenant = (appId, user = null) => { @@ -135,13 +132,14 @@ exports.isUserInAppTenant = (appId, user = null) => { } exports.getTenantIds = async () => { - const db = getDB(PLATFORM_INFO_DB) - let tenants - try { - tenants = await db.get(TENANT_DOC) - } catch (err) { - // if theres an error the doc doesn't exist, no tenants exist - return [] - } - return (tenants && tenants.tenantIds) || [] + return doWithDB(PLATFORM_INFO_DB, async db => { + let tenants + try { + tenants = await db.get(TENANT_DOC) + } catch (err) { + // if theres an error the doc doesn't exist, no tenants exist + return [] + } + return (tenants && tenants.tenantIds) || [] + }) } diff --git a/packages/backend-core/src/tenancy/utils.js b/packages/backend-core/src/tenancy/utils.js new file mode 100644 index 0000000000..70a965ddb7 --- /dev/null +++ b/packages/backend-core/src/tenancy/utils.js @@ -0,0 +1,12 @@ +const { DEFAULT_TENANT_ID } = require("../constants") +const { StaticDatabases, SEPARATOR } = require("../db/constants") + +exports.baseGlobalDBName = tenantId => { + let dbName + if (!tenantId || tenantId === DEFAULT_TENANT_ID) { + dbName = StaticDatabases.GLOBAL.name + } else { + dbName = `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}` + } + return dbName +} diff --git a/packages/backend-core/src/tests/utilities/db.js b/packages/backend-core/src/tests/utilities/db.js deleted file mode 100644 index bb99592d1c..0000000000 --- a/packages/backend-core/src/tests/utilities/db.js +++ /dev/null @@ -1,17 +0,0 @@ -const PouchDB = require("pouchdb") -const env = require("../../environment") - -let POUCH_DB_DEFAULTS - -// should always be test but good to do the sanity check -if (env.isTest()) { - PouchDB.plugin(require("pouchdb-adapter-memory")) - POUCH_DB_DEFAULTS = { - prefix: undefined, - adapter: "memory", - } -} - -const Pouch = PouchDB.defaults(POUCH_DB_DEFAULTS) - -module.exports = Pouch diff --git a/packages/backend-core/src/tests/utilities/dbConfig.js b/packages/backend-core/src/tests/utilities/dbConfig.js index 45b9ff33f9..acd692df40 100644 --- a/packages/backend-core/src/tests/utilities/dbConfig.js +++ b/packages/backend-core/src/tests/utilities/dbConfig.js @@ -1,3 +1,5 @@ -const packageConfiguration = require("../../index") -const CouchDB = require("./db") -packageConfiguration.init(CouchDB) +const core = require("../../index") +const dbConfig = { + inMemory: true, +} +core.init({ db: dbConfig }) diff --git a/packages/backend-core/src/utils.js b/packages/backend-core/src/utils.js index 56205f3487..5c922c42ad 100644 --- a/packages/backend-core/src/utils.js +++ b/packages/backend-core/src/utils.js @@ -10,7 +10,7 @@ const { options } = require("./middleware/passport/jwt") const { queryGlobalView } = require("./db/views") const { Headers, UserStatus, Cookies, MAX_VALID_DATE } = require("./constants") const { - getGlobalDB, + doWithGlobalDB, updateTenantId, getTenantUser, tryAddTenant, @@ -209,82 +209,83 @@ exports.saveUser = async ( // need to set the context for this request, as specified updateTenantId(tenantId) // specify the tenancy incase we're making a new admin user (public) - const db = getGlobalDB(tenantId) - let { email, password, _id } = user - // make sure another user isn't using the same email - let dbUser - if (email) { - // check budibase users inside the tenant - dbUser = await exports.getGlobalUserByEmail(email) - if (dbUser != null && (dbUser._id !== _id || Array.isArray(dbUser))) { - throw `Email address ${email} already in use.` - } - - // check budibase users in other tenants - if (env.MULTI_TENANCY) { - const tenantUser = await getTenantUser(email) - if (tenantUser != null && tenantUser.tenantId !== tenantId) { + return doWithGlobalDB(tenantId, async db => { + let { email, password, _id } = user + // make sure another user isn't using the same email + let dbUser + if (email) { + // check budibase users inside the tenant + dbUser = await exports.getGlobalUserByEmail(email) + if (dbUser != null && (dbUser._id !== _id || Array.isArray(dbUser))) { throw `Email address ${email} already in use.` } - } - // check root account users in account portal - if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { - const account = await accounts.getAccount(email) - if (account && account.verified && account.tenantId !== tenantId) { - throw `Email address ${email} already in use.` + // check budibase users in other tenants + if (env.MULTI_TENANCY) { + const tenantUser = await getTenantUser(email) + if (tenantUser != null && tenantUser.tenantId !== tenantId) { + throw `Email address ${email} already in use.` + } } - } - } else { - dbUser = await db.get(_id) - } - // get the password, make sure one is defined - let hashedPassword - if (password) { - hashedPassword = hashPassword ? await hash(password) : password - } else if (dbUser) { - hashedPassword = dbUser.password - } else if (requirePassword) { - throw "Password must be specified." - } - - _id = _id || 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 = UserStatus.ACTIVE - } - try { - const response = await db.put({ - password: hashedPassword, - ...user, - }) - await tryAddTenant(tenantId, _id, email) - await userCache.invalidateUser(response.id) - return { - _id: response.id, - _rev: response.rev, - email, - } - } catch (err) { - if (err.status === 409) { - throw "User exists already" + // check root account users in account portal + if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { + const account = await accounts.getAccount(email) + if (account && account.verified && account.tenantId !== tenantId) { + throw `Email address ${email} already in use.` + } + } } else { - throw err + dbUser = await db.get(_id) } - } + + // get the password, make sure one is defined + let hashedPassword + if (password) { + hashedPassword = hashPassword ? await hash(password) : password + } else if (dbUser) { + hashedPassword = dbUser.password + } else if (requirePassword) { + throw "Password must be specified." + } + + _id = _id || 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 = UserStatus.ACTIVE + } + try { + const response = await db.put({ + password: hashedPassword, + ...user, + }) + await tryAddTenant(tenantId, _id, email) + await userCache.invalidateUser(response.id) + return { + _id: response.id, + _rev: response.rev, + email, + } + } catch (err) { + if (err.status === 409) { + throw "User exists already" + } else { + throw err + } + } + }) } /** diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index f4f836b1a0..87db3761bc 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -258,6 +258,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/runtime@^7.15.4": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" + integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.16.0", "@babel/template@^7.3.3": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" @@ -857,6 +864,21 @@ aws4@^1.8.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" + integrity sha512-Co3UXiv4npi6lM963mfnuH90/YFLKWWDmoBYfxkHT5xtkSSWNqK9zdG3fw5/CP/dsoKB5aMMJCsgab+tp1OxLQ== + dependencies: + "@babel/runtime" "^7.15.4" + is-retry-allowed "^2.2.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" + babel-jest@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" @@ -1048,7 +1070,7 @@ buffer-from@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.0.0: +buffer-from@1.1.2, buffer-from@^1.0.0: 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== @@ -1139,6 +1161,11 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -1273,6 +1300,11 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +component-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" + 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" @@ -1315,6 +1347,11 @@ cross-spawn@^7.0.0: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" @@ -1777,6 +1814,13 @@ fetch-cookie@0.10.1: dependencies: tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" +fetch-cookie@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== + dependencies: + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -1802,6 +1846,11 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +follow-redirects@^1.14.4: + version "1.14.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" + integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2175,7 +2224,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1: +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" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2226,7 +2275,7 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-buffer@^1.1.5: +is-buffer@^1.1.5, is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -2328,6 +2377,11 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== +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" + integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -2360,7 +2414,7 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= -isarray@1.0.0, isarray@^1.0.0: +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -2824,6 +2878,11 @@ jodid25519@^1.0.0: dependencies: jsbn "~0.1.0" +join-component@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5" + 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" @@ -2902,7 +2961,7 @@ json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= @@ -3204,6 +3263,11 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= +lodash.pick@^4.0.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + lodash@^4.14.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -3252,6 +3316,15 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + memdown@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" @@ -3372,6 +3445,11 @@ ms@2.1.2, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -3399,6 +3477,16 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +ndjson@^1.4.3: + version "1.5.0" + resolved "https://registry.yarnpkg.com/ndjson/-/ndjson-1.5.0.tgz#ae603b36b134bcec347b452422b0bf98d5832ec8" + integrity sha1-rmA7NrE0vOw0e0UkIrC/mNWDLsg= + dependencies: + json-stringify-safe "^5.0.1" + minimist "^1.2.0" + split2 "^2.1.0" + through2 "^2.0.3" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -3409,7 +3497,7 @@ node-fetch@2.6.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== -node-fetch@^2.6.1: +node-fetch@2.6.7, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -3769,6 +3857,42 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +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.yarnpkg.com/pouch-stream/-/pouch-stream-0.4.1.tgz#0c6d8475c9307677627991a2f079b301c3b89bdd" + integrity sha1-DG2EdckwdndieZGi8HmzAcO4m90= + 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-adapter-leveldb-core@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/pouchdb-adapter-leveldb-core/-/pouchdb-adapter-leveldb-core-7.2.2.tgz#e0aa6a476e2607d7ae89f4a803c9fba6e6d05a8a" @@ -3828,6 +3952,11 @@ pouchdb-binary-utils@7.2.2: 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" @@ -3840,6 +3969,28 @@ pouchdb-errors@7.2.2: 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-json@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/pouchdb-json/-/pouchdb-json-7.2.2.tgz#b939be24b91a7322e9a24b8880a6e21514ec5e1f" @@ -3847,6 +3998,16 @@ pouchdb-json@7.2.2: dependencies: vuvuzela "1.0.3" +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" @@ -3860,13 +4021,34 @@ pouchdb-merge@7.2.2: resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-7.2.2.tgz#940d85a2b532d6a93a6cab4b250f5648511bcc16" integrity sha512-6yzKJfjIchBaS7Tusuk8280WJdESzFfQ0sb4jeMUNnrqs4Cx3b0DIEOYTRRD9EJDM+je7D3AZZ4AT0tFw8gb4A== -pouchdb-promise@6.4.3: +pouchdb-promise@6.4.3, pouchdb-promise@^6.0.4: version "6.4.3" resolved "https://registry.yarnpkg.com/pouchdb-promise/-/pouchdb-promise-6.4.3.tgz#74516f4acf74957b54debd0fb2c0e5b5a68ca7b3" 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 sha1-qk+l2PUt9IJTkvGOB8fhGs/8ZQo= + 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" @@ -3881,17 +4063,17 @@ pouchdb-utils@7.2.2: pouchdb-md5 "7.2.2" uuid "8.1.0" -pouchdb@^7.2.1: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-7.2.2.tgz#fcae82862db527e4cf7576ed8549d1384961f364" - integrity sha512-5gf5nw5XH/2H/DJj8b0YkvG9fhA/4Jt6kL0Y8QjtztVjb1y4J19Rg4rG+fUbXu96gsUrlyIvZ3XfM0b4mogGmw== +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.1" + buffer-from "1.1.2" clone-buffer "1.0.0" double-ended-queue "2.1.0-0" - fetch-cookie "0.10.1" + fetch-cookie "0.11.0" immediate "3.3.0" inherits "2.0.4" level "6.0.1" @@ -3900,11 +4082,11 @@ pouchdb@^7.2.1: leveldown "5.6.0" levelup "4.4.0" ltgt "2.2.1" - node-fetch "2.6.0" + node-fetch "2.6.7" readable-stream "1.1.14" - spark-md5 "3.0.1" + spark-md5 "3.0.2" through2 "3.0.2" - uuid "8.1.0" + uuid "8.3.2" vuvuzela "1.0.3" prelude-ls@~1.1.2: @@ -3927,6 +4109,11 @@ private@^0.1.6, private@~0.1.5: resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== +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" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -4012,7 +4199,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@1.1.14: +readable-stream@1.1.14, readable-stream@^1.0.27-1: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= @@ -4036,6 +4223,19 @@ readable-stream@~0.0.2: resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-0.0.4.tgz#f32d76e3fb863344a548d79923007173665b3b8d" integrity sha1-8y124/uGM0SlSNeZIwBxc2ZbO40= +readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readline-sync@^1.4.9: version "1.4.10" resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" @@ -4068,6 +4268,11 @@ redis-parser@^3.0.0: dependencies: redis-errors "^1.0.0" +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -4081,6 +4286,11 @@ remove-trailing-separator@^1.0.1: resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= +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" + integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== + repeat-element@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" @@ -4202,7 +4412,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-buffer@~5.1.1: +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" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -4425,6 +4635,11 @@ spark-md5@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.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== + spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -4458,6 +4673,13 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split2@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" + integrity sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw== + dependencies: + through2 "^2.0.2" + sprintf-js@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" @@ -4548,6 +4770,13 @@ string_decoder@~0.10.x: resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + stringstream@~0.0.4: version "0.0.6" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" @@ -4663,6 +4892,14 @@ through2@3.0.2: inherits "^2.0.4" readable-stream "2 || 3" +through2@^2.0.0, through2@^2.0.2, through2@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -4857,7 +5094,7 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@^1.0.1: +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" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -4877,6 +5114,11 @@ uuid@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.0, uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" @@ -4887,11 +5129,6 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - v8-to-istanbul@^7.0.0: version "7.1.2" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" @@ -5084,7 +5321,7 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xtend@^4.0.2, xtend@~4.0.0: +xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== diff --git a/packages/bbui/package.json b/packages/bbui/package.json index d0399750bc..0a9a093dbb 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.0.105-alpha.45", + "version": "1.0.122", "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.0.105-alpha.45", + "@budibase/string-templates": "^1.0.122", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/builder/package.json b/packages/builder/package.json index 3f8bd78713..e13467a328 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "license": "GPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^1.0.105-alpha.45", - "@budibase/client": "^1.0.105-alpha.45", - "@budibase/frontend-core": "^1.0.105-alpha.45", - "@budibase/string-templates": "^1.0.105-alpha.45", + "@budibase/bbui": "^1.0.122", + "@budibase/client": "^1.0.122", + "@budibase/frontend-core": "^1.0.122", + "@budibase/string-templates": "^1.0.122", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/components/backend/DataTable/formula.js b/packages/builder/src/components/backend/DataTable/formula.js index 42f203ca1c..ea024cdf81 100644 --- a/packages/builder/src/components/backend/DataTable/formula.js +++ b/packages/builder/src/components/backend/DataTable/formula.js @@ -60,6 +60,7 @@ export function getBindings({ ) const label = path == null ? column : `${path}.0.${column}` + const binding = path == null ? `[${column}]` : `${path}.0.[${column}]` // only supply a description for relationship paths const description = path == null @@ -73,8 +74,8 @@ export function getBindings({ description, // don't include path, it messes things up, relationship path // will be replaced by the main array binding - readableBinding: column, - runtimeBinding: `[${column}]`, + readableBinding: label, + runtimeBinding: binding, }) } return bindings diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte index 66d7d43841..c94e750c29 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte @@ -15,7 +15,6 @@ import ArrayRenderer from "components/common/renderers/ArrayRenderer.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import { goto } from "@roxi/routify" - import GoogleButton from "../_components/GoogleButton.svelte" export let datasource export let save @@ -161,11 +160,6 @@ Fetch tables - {#if integration.auth} - {#if integration.auth.type === "google"} - - {/if} - {/if} 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 17e35eda31..e870c2f6db 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 @@ -136,7 +136,7 @@ notifications.success("Request sent successfully") } } catch (error) { - notifications.error("Error running query") + notifications.error(`Query Error: ${error.message}`) } } diff --git a/packages/cli/package.json b/packages/cli/package.json index d95ee9209b..056803a9fe 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 112ef06f8f..251f53ea03 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "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.0.105-alpha.45", - "@budibase/frontend-core": "^1.0.105-alpha.45", - "@budibase/string-templates": "^1.0.105-alpha.45", + "@budibase/bbui": "^1.0.122", + "@budibase/frontend-core": "^1.0.122", + "@budibase/string-templates": "^1.0.122", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/client/src/api/api.js b/packages/client/src/api/api.js index 1d575d9d27..c3cc679220 100644 --- a/packages/client/src/api/api.js +++ b/packages/client/src/api/api.js @@ -34,6 +34,7 @@ export const API = createAPIClient({ // Or we could check error.status and redirect to login on a 403 etc. onError: error => { const { status, method, url, message, handled } = error || {} + const ignoreErrorUrls = ["bbtel", "/api/global/self"] // Log any errors that we haven't manually handled if (!handled) { @@ -45,7 +46,14 @@ export const API = createAPIClient({ if (message) { // Don't notify if the URL contains the word analytics as it may be // blocked by browser extensions - if (!url?.includes("analytics")) { + let ignore = false + for (let ignoreUrl of ignoreErrorUrls) { + if (url?.includes(ignoreUrl)) { + ignore = true + break + } + } + if (!ignore) { notificationStore.actions.error(message) } } diff --git a/packages/client/src/components/app/Icon.svelte b/packages/client/src/components/app/Icon.svelte index 70eb69ce1a..829cc60227 100644 --- a/packages/client/src/components/app/Icon.svelte +++ b/packages/client/src/components/app/Icon.svelte @@ -36,8 +36,13 @@ div { font-style: italic; } - .hoverable:hover { + @media (hover: hover) { + .hoverable:hover { + color: var(--spectrum-alias-icon-color-selected-hover) !important; + cursor: pointer; + } + } + .hoverable:active { color: var(--spectrum-alias-icon-color-selected-hover) !important; - cursor: pointer; } diff --git a/packages/client/yarn.lock b/packages/client/yarn.lock index 6e75172fa1..9ab9b9748d 100644 --- a/packages/client/yarn.lock +++ b/packages/client/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adobe/spectrum-css-workflow-icons@^1.2.1": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.5.3.tgz#5e31ce842b7626f4b99f9d5cd0b17599d287b0bf" + integrity sha512-lWzRWun9kQWHj46Za7riJsl82LasYI90WpeKpJJ9ibZ7s0VT+sStFaRq/zqmp5IxQBfY3xwD4TsKSI26mHdmCA== + "@babel/code-frame@^7.10.4": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" @@ -23,6 +28,104 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@budibase/bbui@^1.0.122": + version "1.0.122" + resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.0.122.tgz#b9297106bf38112e0ea93dbdbc9ed933b3d3efa3" + integrity sha512-aLLWypklGApzLtreNZMELOJE1ak5fXFtXgzavqFib0T7VF+M8IUMP4py0k9EkwoVAXNmJ3cWw3Vx/2eVaoavCA== + dependencies: + "@adobe/spectrum-css-workflow-icons" "^1.2.1" + "@budibase/string-templates" "^1.0.122" + "@spectrum-css/actionbutton" "^1.0.1" + "@spectrum-css/actiongroup" "^1.0.1" + "@spectrum-css/avatar" "^3.0.2" + "@spectrum-css/button" "^3.0.1" + "@spectrum-css/buttongroup" "^3.0.2" + "@spectrum-css/checkbox" "^3.0.2" + "@spectrum-css/dialog" "^3.0.1" + "@spectrum-css/divider" "^1.0.3" + "@spectrum-css/dropzone" "^3.0.2" + "@spectrum-css/fieldgroup" "^3.0.2" + "@spectrum-css/fieldlabel" "^3.0.1" + "@spectrum-css/icon" "^3.0.1" + "@spectrum-css/illustratedmessage" "^3.0.2" + "@spectrum-css/inlinealert" "^2.0.1" + "@spectrum-css/inputgroup" "^3.0.2" + "@spectrum-css/label" "^2.0.10" + "@spectrum-css/link" "^3.1.1" + "@spectrum-css/menu" "^3.0.1" + "@spectrum-css/modal" "^3.0.1" + "@spectrum-css/pagination" "^3.0.3" + "@spectrum-css/picker" "^1.0.1" + "@spectrum-css/popover" "^3.0.1" + "@spectrum-css/progressbar" "^1.0.2" + "@spectrum-css/progresscircle" "^1.0.2" + "@spectrum-css/radio" "^3.0.2" + "@spectrum-css/search" "^3.0.2" + "@spectrum-css/sidenav" "^3.0.2" + "@spectrum-css/statuslight" "^3.0.2" + "@spectrum-css/stepper" "^3.0.3" + "@spectrum-css/switch" "^1.0.2" + "@spectrum-css/table" "^3.0.1" + "@spectrum-css/tabs" "^3.0.1" + "@spectrum-css/tags" "^3.0.2" + "@spectrum-css/textfield" "^3.0.1" + "@spectrum-css/toast" "^3.0.1" + "@spectrum-css/tooltip" "^3.0.3" + "@spectrum-css/treeview" "^3.0.2" + "@spectrum-css/typography" "^3.0.1" + "@spectrum-css/underlay" "^2.0.9" + "@spectrum-css/vars" "^3.0.1" + dayjs "^1.10.4" + easymde "^2.16.1" + svelte-flatpickr "^3.2.3" + svelte-portal "^1.0.0" + +"@budibase/frontend-core@^1.0.122": + version "1.0.122" + resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-1.0.122.tgz#16f60686272d47ca0220b2bdf4c7045d03de296a" + integrity sha512-026Wjf+/mFaXSHZA+Ha4nErrYsIDYEiKlm0acB2TzteNg4O85Onp+VhSFK4OTAwFjysL3yILc5e/O7tdtLXYAA== + dependencies: + "@budibase/bbui" "^1.0.122" + lodash "^4.17.21" + svelte "^3.46.2" + +"@budibase/handlebars-helpers@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.8.tgz#6953d29673a8c5c407e096c0a84890465c7ce841" + integrity sha512-ggWJUt0GqsHFAEup5tlWlcrmYML57nKhpNGGLzVsqXVYN8eVmf3xluYmmMe7fDYhQH0leSprrdEXmsdFQF3HAQ== + dependencies: + array-sort "^1.0.0" + define-property "^2.0.2" + extend-shallow "^3.0.2" + for-in "^1.0.2" + get-object "^0.2.0" + get-value "^3.0.1" + handlebars "^4.7.7" + handlebars-utils "^1.0.6" + has-value "^2.0.2" + helper-md "^0.2.2" + html-tag "^2.0.0" + is-even "^1.0.0" + is-glob "^4.0.1" + kind-of "^6.0.3" + micromatch "^3.1.5" + relative "^3.0.2" + striptags "^3.1.1" + to-gfm-code-block "^0.1.1" + year "^0.2.1" + +"@budibase/string-templates@^1.0.122": + version "1.0.122" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.122.tgz#15e0f9a997b9c18f931704f6ceff0789dc4d4606" + integrity sha512-kd6v31dnNnXWapSMnOMDvqXNR1C14qQZKLesIe/+XegoCsT2CCTVTj64KQC6fe9zvS50ckbTpDHFqNUwGbWwpA== + dependencies: + "@budibase/handlebars-helpers" "^0.11.8" + dayjs "^1.10.4" + handlebars "^4.7.6" + handlebars-utils "^1.0.6" + lodash "^4.17.20" + vm2 "^3.9.4" + "@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" @@ -73,16 +176,46 @@ estree-walker "^1.0.1" picomatch "^2.2.2" -"@spectrum-css/button@^3.0.3": +"@spectrum-css/actionbutton@^1.0.1": + version "1.1.11" + resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.1.11.tgz#1efc6498fd037798762182902205053d2f6847ad" + integrity sha512-XBEXOZYIVj4RnL8I0Ni63gDXY/QWYGCsroqK0Ii+toAM5I8pwtX0fnbz3VlENJl2ycdx13bLkxI+t7CFP8EExg== + +"@spectrum-css/actiongroup@^1.0.1": + version "1.0.23" + resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.23.tgz#395f9a8527d7ca06d488799df43f6611dad05c5b" + integrity sha512-uVoVRyY3K9VSpmQXekWWrciO2NvrkYx0dWWsS/xQmEpCJRaD3fOe317dfHRzVrstPs5sFk5DFeqPLxTSrydxTA== + +"@spectrum-css/avatar@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/avatar/-/avatar-3.0.2.tgz#4f1826223eae330e64b6d3cc899e9bc2e98dac95" + integrity sha512-wEczvSqxttTWSiL3cOvXV/RmGRwSkw2w6+slcHhnf0kb7ovymMM+9oz8vvEpEsSeo5u598bc+7ktrKFpAd6soQ== + +"@spectrum-css/button@^3.0.1", "@spectrum-css/button@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84" integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg== +"@spectrum-css/buttongroup@^3.0.2": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.10.tgz#897ea04b3ffea389fc7fe5bf67a6d1f3454b774d" + integrity sha512-U7D24vgHYhlqOyaLJZ5LPskDAuD7cGZktmWvXtvLqG6RFyTr7JHn5oPRuo6mLzaggIHqCdJylOjZ4FHqT4LpTQ== + "@spectrum-css/card@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b" integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg== +"@spectrum-css/checkbox@^3.0.2": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.1.0.tgz#f0b9861b8cc233a951a3c31811c93c2304735d31" + integrity sha512-tK3lVOQ0vyDtZ3QR1fryCEfJnBG3UBRYApNvsiFguee5g0IsXUHhohcswJO9gH5G6UVmOt9zoKVInTRTxpgjBw== + +"@spectrum-css/dialog@^3.0.1": + version "3.0.12" + resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.12.tgz#fc97e002ca768a3d99dd10cb6a135c2b06052004" + integrity sha512-50rbFa+9eUKT+3uYBX7CkmI7SbQ0Z3CAFwjyjai+itYZ8kf/FcHVFwcLjgrry9scUnKhexMs94kkr0gfQpPe8Q== + "@spectrum-css/divider@^1.0.3": version "1.0.17" resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.17.tgz#cae86fdcb5eb6dae95798ae19ec962e5735fc27f" @@ -90,11 +223,66 @@ dependencies: "@spectrum-css/vars" "^7.0.0" +"@spectrum-css/dropzone@^3.0.2": + version "3.0.22" + resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.22.tgz#b5be5bd95382112be2b66092c8adcd077e4a8e14" + integrity sha512-pC3lNvfwKJ4TUR4iSrnW/FsiThetK6IiFJpqtI0AoO9tbGzHOSjCfsMqLKefyXioshLNX5iy1xEYvQietHKE9Q== + +"@spectrum-css/fieldgroup@^3.0.2": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.1.0.tgz#0435554bbef0e6a6774a281a4eb1412c194ce31f" + integrity sha512-VjCCuzknhTVf3yY+LYAF6a2Z9sbyWtdv29ZTQ1jYwZk4dFix94AXFk5OLioJ6g8RF1DqQ4ofn4BxDSbeZR0RZQ== + +"@spectrum-css/fieldlabel@^3.0.1": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449" + integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ== + +"@spectrum-css/icon@^3.0.1": + version "3.0.20" + resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.20.tgz#f6580518aa7f54cf0b113718a20f9205ace2c87d" + integrity sha512-M4cYDCKm2apt9R/w2DCtdg7oKSRTbWrpi0aBswh8bDzVGIwJqln76MwlKb/0+Dm7lmbT9cvj1v15ZUHqWT7aGw== + +"@spectrum-css/illustratedmessage@^3.0.2": + version "3.0.17" + resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.17.tgz#49cb2549fda97a6812156bfba6ccdd3a18bebd11" + integrity sha512-kpDqeq1U+rEjG1XuiXkbGvS71vn6mpFF/hiwCgFJWudVOfypDPQ4KLfYw1ditFSUzMCm5H6U/RqAShAJn8oMWA== + +"@spectrum-css/inlinealert@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.6.tgz#4c5e923a1f56a96cc1adb30ef1f06ae04f2c6376" + integrity sha512-OpvvoWP02wWyCnF4IgG8SOPkXymovkC9cGtgMS1FdDubnG3tJZB/JeKTsRR9C9Vt3WBaOmISRdSKlZ4lC9CFzA== + +"@spectrum-css/inputgroup@^3.0.2": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.8.tgz#fc23afc8a73c24d17249c9d2337e8b42085b298b" + integrity sha512-cmQWzFp0GU+4IMc8SSeVFdmQDlRUdPelXaQdKUR9mZuO2iYettg37s0lfBCeJyYkUNTagz0zP8O7A0iXfmeE6g== + +"@spectrum-css/label@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001" + integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ== + +"@spectrum-css/link@^3.1.1": + version "3.1.20" + resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.20.tgz#73fe6f262910ace4380ed0648e163deb13dba788" + integrity sha512-3MdfGYZYrhXkwCkrIQhfk/5vCLbpInU6T2xeUKUZcHEM6eGbIgfZ2GUm18Sv1EpOORF2ZHz8kioBhoUw9k7emA== + "@spectrum-css/link@^3.1.3": version "3.1.17" resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.17.tgz#efa8fd5ee8a6b291843dcaf4fa1270b81c564c48" integrity sha512-sWWTnDB+Yig9WmLvzcvUgSH6zZtu2tWfobMivFLjRnfQYIhxJSoj87AleLpcTbvIQIwSwytSdnbncsm4rBfDjg== +"@spectrum-css/menu@^3.0.1": + version "3.0.21" + resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.21.tgz#d1f7e6e69d30b5e1edd7ed2c86ea4e08dfd670ab" + integrity sha512-G5AIUO26O6IAc6HUGZu4AZgyw0QRyLfSbcKlFGu4oJHzP36cQc1S1uCh8Xp4g5d+n6mU62LxNDLSMpVbwnA00A== + +"@spectrum-css/modal@^3.0.1": + version "3.0.19" + resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.19.tgz#500524f7381b5c6fb1c76262100243565d9d93f4" + integrity sha512-V4yJ83AdRc26G4eEdr/F43mJAVyy1oUcfXZNnavw7ahU4P6dpxfhcGBxAqda5OBUcyY+ThmO8prErO1JIKGIFw== + "@spectrum-css/page@^3.0.1": version "3.0.9" resolved "https://registry.yarnpkg.com/@spectrum-css/page/-/page-3.0.9.tgz#f8a705dee90af958e2ee20307218e4f82a018c36" @@ -102,16 +290,111 @@ dependencies: "@spectrum-css/vars" "^4.3.1" +"@spectrum-css/pagination@^3.0.3": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.11.tgz#68d9f34fe8eb36bf922e41b11f49eac62ac2fc41" + integrity sha512-wjZr7NAcqHK6fxNIGKTYEVtAOJugJTbcz4d8K7DZuUDgBVwLJJHJBi4uJ4KrIRYliMWOvqWTZzCJLmmTfx4cyw== + +"@spectrum-css/picker@^1.0.1": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.2.5.tgz#483722e4c16074a21b2d2625b7a5774819b8407e" + integrity sha512-eojRT2qwjnAbonVPLUEAFFQH+JDP3StgxZrNJ0N88ufupfEqhVxJVtHirrCDLw7zjdFtqGCv80mufeuwdx5XFA== + +"@spectrum-css/popover@^3.0.1": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.11.tgz#a7450c01bcf1609264b4a9df58821368b9e224d1" + integrity sha512-bzyNQJVw6Mn1EBelTaRlXCdd0ZfykNX9O6SHx3a+jXPYu8VBrRpHm0gsfWzPAz1etd1vj1CxwG/teQt4qvyZ/Q== + +"@spectrum-css/progressbar@^1.0.2": + version "1.0.26" + resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.26.tgz#de0d841708a67ca16de482bb82808b62a9bf2bc6" + integrity sha512-vBtBhElKI+J4ugDIHiXyqfLzke7CuBn+UZTZJ90fuyED3HBbWw2VhjfOwrJm6HgbICgLqSQqnqyyWfMeaXO2Lg== + +"@spectrum-css/progresscircle@^1.0.2": + version "1.0.19" + resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.19.tgz#d646d8caaf4106d4a11ae315705e0d22ed46594f" + integrity sha512-T9GrlxobBxJjG8Rc212bHrhF7iHTHQjk9hl23R0laCDZ6KzxWQ5nUE9/DRdDD7VlmJCMX6SChh3A+yac3sylwA== + +"@spectrum-css/radio@^3.0.2": + version "3.0.20" + resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.20.tgz#a1927c43cc3d47d59c626ba5c30af4879933adfd" + integrity sha512-4zEnxtJp62yfMA31DZGV/hpSXMnSeLEhBpkmbUE9VJEf9GrS4G4iKhTHsf8PzOHaYd3kuNov+7pwU7lJxifR1Q== + +"@spectrum-css/search@^3.0.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.1.2.tgz#8d43f35f884f7c190e7694c8d26a3f2cfed01ef0" + integrity sha512-8cMK1QB07dbReZ/ECyTyoT2dELZ7hK1b3jEDiWSeLBbXcKirR1OI24sZEnewQY/XWFd/62Z1YdNaaA8S6UuXWQ== + +"@spectrum-css/sidenav@^3.0.2": + version "3.0.20" + resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.20.tgz#a8d4714c20a863c8c001adc8874a16217aebaf79" + integrity sha512-/kYHaMBVcdOii8o17shT/tvuh/3cZTnT3oqkhBOIYKlP9YxptGW8vM/mHrfcg4ZLKTwYIzDHqAAkWkfPMWDtvQ== + +"@spectrum-css/statuslight@^3.0.2": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.8.tgz#3b0ea80712573679870a85d469850230e794a0f7" + integrity sha512-zMTHs8lk+I7fLdi9waEEbsCmJ1FxeHcjQ0yltWxuRmGk2vl4MQdQIuHIMI63iblqEaiwnJRjXJoKnWlNvndTJQ== + +"@spectrum-css/stepper@^3.0.3": + version "3.0.22" + resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.22.tgz#3bf040d803153abe1ce6e968186bb86f96dbf01f" + integrity sha512-zWWqZEDX/dFwl3OJfg9HcNMRIBlMifxe6+U2r+3H0wem1zf+o/clH+TaLIAl+E5Fd+ZB9hlLH8X7i5rjUEZMNQ== + +"@spectrum-css/switch@^1.0.2": + version "1.0.19" + resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.19.tgz#04cfc3ce8ccabfbf8c83dad8ba7db13513d61037" + integrity sha512-HYl3eM7G0oBfNRAGmPDkuHRO50vgQgsrIeKq71lE0+4QlI10nBNxS388o1MrMHrOPESo3M8ZNkHfX2ImcIPx6A== + +"@spectrum-css/table@^3.0.1": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.3.tgz#7f7f19905ef3275cbf907ce3a5818e63c30b2caf" + integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg== + +"@spectrum-css/tabs@^3.0.1": + version "3.2.12" + resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.12.tgz#9b08f23d5aa881b3441af7757800c7173e5685ff" + integrity sha512-rPFUW9SSW4+3/UJ3UrtY2/l3sQvlqB1fqxHLPDjgykvbfrnMejcCTNV4ZrFNHXpE/6+kGnk+yVViSPtWGwJzkA== + "@spectrum-css/tag@^3.1.4": version "3.3.5" resolved "https://registry.yarnpkg.com/@spectrum-css/tag/-/tag-3.3.5.tgz#f83ded301c8ed334d2c9a33f586807a3d423e588" integrity sha512-KhUZ75xzjnbYPg1ztwWp5xvWYVkG5+KH/2OiTsE5vA9LXZ3Z1O21c5YpFg5FVCvAWN/fwfwpxsi7sp38x7FlLg== -"@spectrum-css/typography@^3.0.2": +"@spectrum-css/tags@^3.0.2": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.3.tgz#fc76d2735cdc442de91b7eb3bee49a928c0767ac" + integrity sha512-SL8vPxVDfWcY5VdIuyl0TImEXcOU1I7yCyXkk7MudMwfnYs81FaIyY32hFV9OHj0Tz/36UzRzc7AVMSuRQ53pw== + +"@spectrum-css/textfield@^3.0.1": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.2.0.tgz#242628992b802c0a68b648c49f1750c8a930a847" + integrity sha512-9VVarhtA9e234eLkneClnHmWkaLI04kZzwphV420KaW6bUEvbKOWYv/elzZy7stJ/ZHbnfKTUC+OgpI8C1tD2A== + +"@spectrum-css/toast@^3.0.1": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.3.tgz#97c1527384707600832ecda35643ed304615250f" + integrity sha512-CjLeaMs+cjUXojCCRtbj0YkD2BoZW16kjj2o5omkEpUTjA34IJ8xJ1a+CCtDILWekhXvN0MBN4sbumcnwcnx8w== + +"@spectrum-css/tooltip@^3.0.3": + version "3.1.14" + resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.1.14.tgz#1384bc035643dbc1ab78c11e7bd4dc7ff768b608" + integrity sha512-jubXE+XqIMiAnRmj3P0A7nOER0LfF1BwK/eG9LI8h/l9tMpkQxc9RFMRUGzjS6ROikumt98yFuau4LifOuV90Q== + +"@spectrum-css/treeview@^3.0.2": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046" + integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw== + +"@spectrum-css/typography@^3.0.1", "@spectrum-css/typography@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38" integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA== +"@spectrum-css/underlay@^2.0.9": + version "2.0.28" + resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.28.tgz#34d51cc27d077ec213e8c584cd893105a77a3cbf" + integrity sha512-2gqaa7t2ywR6IVzJProXS9zYzUXOXZoshnLCm2p4EKykAQNtT5bdRRKuBVuB+R0ucQ64muU+7W5SnLlx23Rwaw== + "@spectrum-css/vars@^3.0.1": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999" @@ -132,11 +415,23 @@ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== +"@types/codemirror@^5.60.4": + version "5.60.5" + resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.5.tgz#5b989a3b4bbe657458cf372c92b6bfda6061a2b7" + integrity sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg== + dependencies: + "@types/tern" "*" + "@types/estree@*", "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/marked@^4.0.1": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.3.tgz#2098f4a77adaba9ce881c9e0b6baf29116e5acc4" + integrity sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg== + "@types/node@*": version "16.11.7" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" @@ -149,6 +444,23 @@ dependencies: "@types/node" "*" +"@types/tern@*": + version "0.23.4" + resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" + integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== + dependencies: + "@types/estree" "*" + +acorn-walk@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +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== + alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -185,11 +497,77 @@ apexcharts@^3.19.2, apexcharts@^3.22.1: svg.resize.js "^1.4.3" svg.select.js "^3.0.1" +argparse@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-sort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" + integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autolinker@~0.28.0: + version "0.28.1" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" + integrity sha1-BlK0kYgYefB3XazgzcoyM5QqTkc= + dependencies: + gulp-header "^1.7.1" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -208,6 +586,22 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6: version "4.18.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" @@ -229,6 +623,21 @@ builtin-modules@^3.1.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887" integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA== +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -261,6 +670,16 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -270,6 +689,26 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +codemirror-spell-checker@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz#1c660f9089483ccb5113b9ba9ca19c3f4993371e" + integrity sha1-HGYPkIlIPMtRE7m6nKGcP0mTNx4= + dependencies: + typo-js "*" + +codemirror@^5.63.1: + version "5.65.3" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.3.tgz#2d029930d5a293bc5fb96ceea64654803c0d4ac7" + integrity sha512-kCC0iwGZOVZXHEKW3NDTObvM7pTIyowjty4BUqeREROc/3I6bWbgZDA3fGDwlA+rbgRjvnRnfqs9SfXynel1AQ== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -314,18 +753,33 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-with-sourcemaps@^1.1.0: +concat-with-sourcemaps@*, concat-with-sourcemaps@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== dependencies: source-map "^0.6.1" +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +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" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + css-declaration-sorter@^6.0.3: version "6.1.3" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2" @@ -419,21 +873,67 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" +dayjs@^1.10.4: + version "1.11.1" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.1.tgz#90b33a3dda3417258d48ad2771b415def6545eb0" + integrity sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA== + dayjs@^1.10.5: version "1.10.8" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.8.tgz#267df4bc6276fcb33c04a6735287e3f429abec41" integrity sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow== +debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + define-lazy-prop@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + dom-serializer@^1.0.1: version "1.3.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" @@ -476,6 +976,17 @@ downloadjs@1.4.7: resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c" integrity sha1-9p+W+UDg0FU9rCkROYZaPNAQHjw= +easymde@^2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/easymde/-/easymde-2.16.1.tgz#f4c2380312615cb33826f1a1fecfaa4022ff551a" + integrity sha512-FihYgjRsKfhGNk89SHSqxKLC4aJ1kfybPWW6iAmtb5GnXu+tnFPSzSaGBmk1RRlCuhFSjhF0SnIMGVPjEzkr6g== + dependencies: + "@types/codemirror" "^5.60.4" + "@types/marked" "^4.0.1" + codemirror "^5.63.1" + codemirror-spell-checker "1.1.2" + marked "^4.0.10" + electron-to-chromium@^1.3.896: version "1.3.900" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.900.tgz#5be2c5818a2a012c511b4b43e87b6ab7a296d4f5" @@ -491,6 +1002,11 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== +ent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + entities@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -536,11 +1052,80 @@ eventemitter3@^4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + flatpickr@^4.5.2: version "4.6.9" resolved "https://registry.yarnpkg.com/flatpickr/-/flatpickr-4.6.9.tgz#9a13383e8a6814bda5d232eae3fcdccb97dc1499" integrity sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw== +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0= + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -568,6 +1153,26 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-object@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" + integrity sha1-2S/31RkMZFMM2gVD2sY6PUf+jAw= + dependencies: + is-number "^2.0.2" + isobject "^0.2.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +get-value@^3.0.0, get-value@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" + integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== + dependencies: + isobject "^3.0.1" + glob@^7.1.6: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -580,6 +1185,35 @@ glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +gulp-header@^1.7.1: + version "1.8.12" + resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" + integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== + dependencies: + concat-with-sourcemaps "*" + lodash.template "^4.4.0" + through2 "^2.0.0" + +handlebars-utils@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" + integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== + dependencies: + kind-of "^6.0.0" + typeof-article "^0.1.1" + +handlebars@^4.7.6, handlebars@^4.7.7: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -590,6 +1224,52 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-value@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" + integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA== + dependencies: + get-value "^3.0.0" + has-values "^2.0.1" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-values@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" + integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w== + dependencies: + kind-of "^6.0.2" + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -597,6 +1277,24 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +helper-md@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" + integrity sha1-wfWdflW7riM2L9ig6XFgeuxp1B8= + dependencies: + ent "^2.2.0" + extend-shallow "^2.0.1" + fs-exists-sync "^0.1.0" + remarkable "^1.6.2" + +html-tag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" + integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== + dependencies: + is-self-closing "^1.0.1" + kind-of "^6.0.0" + htmlparser2@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" @@ -639,7 +1337,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -649,6 +1347,25 @@ is-absolute-url@^3.0.3: resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + 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" @@ -656,21 +1373,112 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-even@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" + integrity sha1-drUFX7rY0pSoa2qUkBXhyXtxfAY= + dependencies: + is-odd "^0.1.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + 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" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= +is-number@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-odd@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" + integrity sha1-vFc7XONx7yqtbm9JeZtyvvE5eKc= + dependencies: + is-number "^3.0.0" + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + is-plain-object@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" @@ -688,6 +1496,18 @@ is-resolvable@^1.1.0: resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== +is-self-closing@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" + integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== + dependencies: + self-closing-tags "^1.0.1" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -695,6 +1515,28 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isobject@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" + integrity sha1-o0MhkvObkQtfAsyYlIeDbscKqF4= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + jest-worker@^26.2.1: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" @@ -716,6 +1558,30 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0, kind-of@^5.0.2: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + leaflet@^1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.7.1.tgz#10d684916edfe1bf41d688a3b97127c0322a2a19" @@ -735,6 +1601,11 @@ loader-utils@^1.1.0: emojis-list "^3.0.0" json5 "^1.0.1" +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -745,11 +1616,31 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= +lodash.template@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= +lodash@^4.17.20, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + magic-string@^0.25.7: version "0.25.7" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" @@ -757,6 +1648,23 @@ magic-string@^0.25.7: dependencies: sourcemap-codec "^1.4.4" +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +marked@^4.0.10: + version "4.0.14" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.14.tgz#7a3a5fa5c80580bac78c1ed2e3b84d7bd6fc3870" + integrity sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ== + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -767,6 +1675,25 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +micromatch@^3.1.5: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -774,10 +1701,23 @@ minimatch@^3.0.2, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= nanoid@^2.1.0: version "2.1.11" @@ -790,9 +1730,31 @@ nanoid@^3.1.30, nanoid@^3.1.32: integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== nanoid@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557" - integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA== + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== node-releases@^2.0.1: version "2.0.1" @@ -811,6 +1773,29 @@ nth-check@^2.0.0: dependencies: boolbase "^1.0.0" +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -852,6 +1837,11 @@ parse-srcset@^1.0.2: resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE= +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + 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" @@ -877,6 +1867,11 @@ pify@^5.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + postcss-calc@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a" @@ -1163,6 +2158,11 @@ postcss@^8.3.11: picocolors "^1.0.0" source-map-js "^1.0.2" +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" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + promise.series@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd" @@ -1175,6 +2175,27 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" +readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + regexparam@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.0.tgz#059476767d5f5f87f735fc7922d133fd1a118c8c" @@ -1185,6 +2206,31 @@ regexparam@^1.3.0: resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== +relative@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" + integrity sha1-Dc2OxUpdNaPBXhBFA9ZTdbWlNn8= + dependencies: + isobject "^2.0.0" + +remarkable@^1.6.2: + version "1.7.4" + resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" + integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== + dependencies: + argparse "^1.0.10" + autolinker "~0.28.0" + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -1200,6 +2246,11 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + resolve@^1.17.0, resolve@^1.19.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" @@ -1208,6 +2259,11 @@ resolve@^1.17.0, resolve@^1.19.0: is-core-module "^2.2.0" path-parse "^1.0.6" +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + rollup-plugin-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz#a18da0a4b30bf5ca1ee76ddb1422afbb84ae2b9e" @@ -1298,7 +2354,7 @@ rollup@^2.44.0: optionalDependencies: fsevents "~2.3.2" -safe-buffer@^5.1.0: +safe-buffer@^5.1.0, 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" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -1308,6 +2364,13 @@ safe-identifier@^0.4.2: resolved "https://registry.yarnpkg.com/safe-identifier/-/safe-identifier-0.4.2.tgz#cf6bfca31c2897c588092d1750d30ef501d59fcb" integrity sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w== +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + sanitize-html@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.0.tgz#e106205b468aca932e2f9baf241f24660d34e279" @@ -1325,6 +2388,11 @@ screenfull@^6.0.1: resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.1.tgz#3b71e6f06b72d817a8d3be73c45ebe71fa8da1ce" integrity sha512-yzQW+j4zMUBQC51xxWaoDYjxOtl8Kn+xvue3p6v/fv2pIi1jH4AldgVLU8TBfFVgH2x3VXlf3+YiA/AYIPlaew== +self-closing-tags@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" + integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== + serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" @@ -1332,6 +2400,16 @@ serialize-javascript@^4.0.0: dependencies: randombytes "^2.1.0" +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + shortid@^2.2.15: version "2.2.16" resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608" @@ -1344,11 +2422,52 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + source-map-js@^1.0.1, source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + 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" @@ -1357,6 +2476,16 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -1372,11 +2501,31 @@ sourcemap-codec@^1.4.4: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + string-hash@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" @@ -1391,6 +2540,13 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.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" @@ -1398,6 +2554,11 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +striptags@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" + integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== + style-inject@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/style-inject/-/style-inject-0.3.0.tgz#d21c477affec91811cc82355832a700d22bf8dd3" @@ -1432,13 +2593,18 @@ svelte-apexcharts@^1.0.2: dependencies: apexcharts "^3.19.2" -svelte-flatpickr@^3.1.0: +svelte-flatpickr@^3.1.0, svelte-flatpickr@^3.2.3: version "3.2.6" resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-3.2.6.tgz#595a97b2f25a669e61fe743f90a10dce783bbd49" integrity sha512-0ePUyE9OjInYFqQwRKOxnFSu4dQX9+/rzFMynq2fKYXx406ZUThzSx72gebtjr0DoAQbsH2///BBZa5qk4qZXg== dependencies: flatpickr "^4.5.2" +svelte-portal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" + integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== + svelte-spa-router@^3.0.5: version "3.2.0" resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-3.2.0.tgz#fae3311d292451236cb57131262406cf312b15ee" @@ -1451,6 +2617,11 @@ svelte@^3.38.2: resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.46.4.tgz#0c46bc4a3e20a2617a1b7dc43a722f9d6c084a38" integrity sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg== +svelte@^3.46.2: + version "3.47.0" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.47.0.tgz#ba46fe4aea99fc650d6939c215cd4694f5325a19" + integrity sha512-4JaJp3HEoTCGARRWZQIZDUanhYv0iyoHikklVHVLH9xFE9db22g4TDv7CPeNA8HD1JgjXI1vlhR1JZvvhaTu2Q== + svg.draggable.js@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba" @@ -1528,16 +2699,112 @@ terser@^5.0.0: source-map "~0.7.2" source-map-support "~0.5.20" +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + timsort@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -util-deprecate@^1.0.2: +to-gfm-code-block@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" + integrity sha1-JdBFpfrlUxielje1kJANpzLYqoI= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +typeof-article@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" + integrity sha1-nwfnM8P7tkb/qeYcCN66zUYOBq8= + dependencies: + kind-of "^3.1.0" + +typo-js@*: + version "1.2.1" + resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.2.1.tgz#334a0d8c3f6c56f2f1e15fdf6c31677793cbbe9b" + integrity sha512-bTGLjbD3WqZDR3CgEFkyi9Q/SS2oM29ipXrWfDb4M74ea69QwKAECVceYpaBu0GfdnASMg9Qfl67ttB23nePHg== + +uglify-js@^3.1.4: + version "3.15.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.4.tgz#fa95c257e88f85614915b906204b9623d4fa340d" + integrity sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +vm2@^3.9.4: + version "3.9.9" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.9.tgz#c0507bc5fbb99388fad837d228badaaeb499ddc5" + integrity sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw== + dependencies: + acorn "^8.7.0" + acorn-walk "^8.2.0" + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -1552,6 +2819,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + 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" @@ -1579,3 +2851,8 @@ yargs@^17.3.1: string-width "^4.2.3" y18n "^5.0.5" yargs-parser "^21.0.0" + +year@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" + integrity sha1-QIOuUgoxiyPshgN/MADLiSvfm7A= diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index ac5b55a7f3..57e5f67f72 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "^1.0.105-alpha.45", + "@budibase/bbui": "^1.0.122", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/server/package.json b/packages/server/package.json index 2a846e0ece..c7ca31f6c3 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "description": "Budibase Web Server", "main": "src/index.ts", "repository": { @@ -68,10 +68,10 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "^10.0.3", - "@budibase/backend-core": "^1.0.105-alpha.45", - "@budibase/client": "^1.0.105-alpha.45", - "@budibase/pro": "1.0.105-alpha.45", - "@budibase/string-templates": "^1.0.105-alpha.45", + "@budibase/backend-core": "^1.0.122", + "@budibase/client": "^1.0.122", + "@budibase/string-templates": "^1.0.122", + "@budibase/pro": "1.0.105-alpha.43", "@bull-board/api": "^3.7.0", "@bull-board/koa": "^3.7.0", "@elastic/elasticsearch": "7.10.0", @@ -121,7 +121,7 @@ "pg": "8.5.1", "pino-pretty": "4.0.0", "posthog-node": "^1.1.4", - "pouchdb": "7.2.1", + "pouchdb": "7.3.0", "pouchdb-adapter-memory": "^7.2.1", "pouchdb-all-dbs": "1.0.2", "pouchdb-find": "^7.2.2", diff --git a/packages/server/scripts/exportAppTemplate.js b/packages/server/scripts/exportAppTemplate.js index 8b641f7c92..bb1de425ba 100755 --- a/packages/server/scripts/exportAppTemplate.js +++ b/packages/server/scripts/exportAppTemplate.js @@ -2,7 +2,8 @@ const yargs = require("yargs") const fs = require("fs") const { join } = require("path") -const CouchDB = require("../src/db") +require("../src/db").init() +const { doWithDB } = require("@budibase/backend-core/db") // load environment const env = require("../src/environment") const { @@ -47,13 +48,14 @@ yargs const writeStream = fs.createWriteStream(join(exportPath, "dump.text")) // perform couch dump - const instanceDb = new CouchDB(appId) - await instanceDb.dump(writeStream, { - filter: doc => - !( - doc._id.includes(USER_METDATA_PREFIX) || - doc.includes(LINK_USER_METADATA_PREFIX) - ), + await doWithDB(appId, async db => { + return db.dump(writeStream, { + filter: doc => + !( + doc._id.includes(USER_METDATA_PREFIX) || + doc.includes(LINK_USER_METADATA_PREFIX) + ), + }) }) console.log(`Template ${name} exported to ${exportPath}`) } diff --git a/packages/server/scripts/integrations/mysql/init.sql b/packages/server/scripts/integrations/mysql/init.sql index 9fa608f42d..15269f2f41 100644 --- a/packages/server/scripts/integrations/mysql/init.sql +++ b/packages/server/scripts/integrations/mysql/init.sql @@ -26,6 +26,7 @@ CREATE TABLE Products ( updated time ); INSERT INTO Persons (FirstName, LastName, Age, Address, City, CreatedAt) VALUES ('Mike', 'Hughes', 28.2, '123 Fake Street', 'Belfast', '2021-01-19 03:14:07'); +INSERT INTO Persons (FirstName, LastName, Age, Address, City, CreatedAt) VALUES ('Dave', 'Johnson', 29, '124 Fake Street', 'Belfast', '2022-04-01 00:11:11'); INSERT INTO Tasks (PersonID, TaskName, CreatedAt) VALUES (1, 'assembling', '2020-01-01'); INSERT INTO Tasks (PersonID, TaskName, CreatedAt) VALUES (2, 'processing', '2019-12-31'); INSERT INTO Products (name, updated) VALUES ('Meat', '11:00:22'), ('Fruit', '10:00:00'); diff --git a/packages/server/scripts/replicateApp.js b/packages/server/scripts/replicateApp.js deleted file mode 100644 index 6730fe42d3..0000000000 --- a/packages/server/scripts/replicateApp.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Script to replicate your PouchDb (in your home directory) to a remote CouchDB - * USAGE... - * node scripts/replicateApp - * e.g. node scripts/replicateApp Mike http://admin:password@127.0.0.1:5984 - */ - -const CouchDB = require("../src/db") -const { DocumentTypes } = require("../src/db/utils") -const { getAllDbs } = require("@budibase/backend-core/db") - -const appName = process.argv[2].toLowerCase() -const remoteUrl = process.argv[3] - -console.log(`Replicating from ${appName} to ${remoteUrl}/${appName}`) - -const run = async () => { - const dbs = await getAllDbs() - const appDbNames = dbs.filter(dbName => dbName.startsWith("inst_app")) - let apps = [] - for (let dbName of appDbNames) { - const db = new CouchDB(dbName) - apps.push(db.get(DocumentTypes.APP_METADATA)) - } - apps = await Promise.all(apps) - const app = apps.find( - a => a.name === appName || a.name.toLowerCase() === appName - ) - - if (!app) { - console.log( - `Could not find app... apps: ${apps.map(app => app.name).join(", ")}` - ) - return - } - - const instanceDb = new CouchDB(app.appId) - const remoteDb = new CouchDB(`${remoteUrl}/${appName}`) - - instanceDb.replicate - .to(remoteDb) - .on("complete", function () { - console.log("SUCCESS!") - }) - .on("error", function (err) { - console.log(`FAILED: ${err}`) - }) -} - -run() diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 41d6235337..4e6d37765f 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -131,7 +131,7 @@ async function createInstance(template: any) { const tenantId = isMultiTenant() ? getTenantId() : null const baseAppId = generateAppID(tenantId) const appId = generateDevAppID(baseAppId) - updateAppId(appId) + await updateAppId(appId) const db = getAppDB() await db.put({ @@ -471,6 +471,8 @@ export const sync = async (ctx: any, next: any) => { }) } catch (err) { error = err + } finally { + await replication.close() } // sync the users diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index c18d2c992d..cd0145e2d6 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -93,6 +93,7 @@ async function initDeployedApp(prodAppId: any) { } async function deployApp(deployment: any) { + let replication try { const appId = getAppId() const devAppId = getDevelopmentAppID(appId) @@ -102,10 +103,9 @@ async function deployApp(deployment: any) { source: devAppId, target: productionAppId, } - const replication = new Replication(config) + replication = new Replication(config) console.log("Replication object created") - await replication.replicate() console.log("replication complete.. replacing app meta doc") const db = getProdAppDB() @@ -129,6 +129,10 @@ async function deployApp(deployment: any) { ...err, message: `Deployment Failed: ${err.message}`, } + } finally { + if (replication) { + await replication.close() + } } } diff --git a/packages/server/src/api/controllers/dev.js b/packages/server/src/api/controllers/dev.js index 54f554e358..509089bed9 100644 --- a/packages/server/src/api/controllers/dev.js +++ b/packages/server/src/api/controllers/dev.js @@ -83,7 +83,9 @@ exports.revert = async ctx => { try { const db = getProdAppDB({ skip_setup: true }) const info = await db.info() - if (info.error) throw info.error + if (info.error) { + throw info.error + } const deploymentDoc = await db.get(DocumentTypes.DEPLOYMENTS) if ( !deploymentDoc.history || @@ -95,12 +97,11 @@ exports.revert = async ctx => { return ctx.throw(400, "App has not yet been deployed") } + const replication = new Replication({ + source: productionAppId, + target: appId, + }) try { - const replication = new Replication({ - source: productionAppId, - target: appId, - }) - await replication.rollback() // update appID in reverted app to be dev version again const db = getAppDB() @@ -114,6 +115,8 @@ exports.revert = async ctx => { } } catch (err) { ctx.throw(400, `Unable to revert. ${err}`) + } finally { + await replication.close() } } diff --git a/packages/server/src/api/controllers/query/import/tests/index.spec.js b/packages/server/src/api/controllers/query/import/tests/index.spec.js index 0cfb4f4f19..f207213587 100644 --- a/packages/server/src/api/controllers/query/import/tests/index.spec.js +++ b/packages/server/src/api/controllers/query/import/tests/index.spec.js @@ -1,12 +1,4 @@ - -const bulkDocs = jest.fn() -const db = jest.fn(() => { - return { - bulkDocs - } -}) -jest.mock("../../../../../db", () => db) -require("@budibase/backend-core").init(require("../../../../../db")) +const TestConfig = require("../../../../../tests/utilities/TestConfiguration") const { RestImporter } = require("../index") @@ -48,6 +40,12 @@ const datasets = { } describe("Rest Importer", () => { + const config = new TestConfig(false) + + beforeEach(async () => { + await config.init() + }) + let restImporter const init = async (data) => { @@ -105,11 +103,9 @@ describe("Rest Importer", () => { const testImportQueries = async (key, data, assertions) => { await init(data) - bulkDocs.mockReturnValue([]) const importResult = await restImporter.importQueries("datasourceId") expect(importResult.errorQueries.length).toBe(0) expect(importResult.queries.length).toBe(assertions[key].count) - expect(bulkDocs).toHaveBeenCalledTimes(1) jest.clearAllMocks() } diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 1e3a300afd..d7063e590b 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -323,6 +323,28 @@ module External { return { row: newRow, manyRelationships } } + squashRelationshipColumns( + table: Table, + row: Row, + relationships: RelationshipsJson[] + ): Row { + for (let relationship of relationships) { + const linkedTable = this.tables[relationship.tableName] + if (!linkedTable || !row[relationship.column]) { + continue + } + const display = linkedTable.primaryDisplay + for (let key of Object.keys(row[relationship.column])) { + const related: Row = row[relationship.column][key] + row[relationship.column][key] = { + primaryDisplay: display ? related[display] : undefined, + _id: related._id, + } + } + } + return row + } + /** * This iterates through the returned rows and works out what elements of the rows * actually match up to another row (based on primary keys) - this is pretty specific @@ -354,12 +376,6 @@ module External { if (!linked._id) { continue } - // if not returning full docs then get the minimal links out - const display = linkedTable.primaryDisplay - linked = { - primaryDisplay: display ? linked[display] : undefined, - _id: linked._id, - } columns[relationship.column] = linked } for (let [column, related] of Object.entries(columns)) { @@ -417,7 +433,9 @@ module External { relationships ) } - return processFormulas(table, Object.values(finalRows)) + return processFormulas(table, Object.values(finalRows)).map((row: Row) => + this.squashRelationshipColumns(table, row, relationships) + ) } /** diff --git a/packages/server/src/api/controllers/row/internal.js b/packages/server/src/api/controllers/row/internal.js index d8e18df43b..b2b932a69a 100644 --- a/packages/server/src/api/controllers/row/internal.js +++ b/packages/server/src/api/controllers/row/internal.js @@ -6,6 +6,7 @@ const { DocumentTypes, InternalTables, } = require("../../../db/utils") +const { dangerousGetDB } = require("@budibase/backend-core/db") const userController = require("../user") const { inputProcessing, @@ -250,7 +251,7 @@ exports.fetch = async ctx => { } exports.find = async ctx => { - const db = getAppDB() + const db = dangerousGetDB(ctx.appId) const table = await db.get(ctx.params.tableId) let row = await findRow(ctx, ctx.params.tableId, ctx.params.rowId) row = await outputProcessing(table, row) diff --git a/packages/server/src/api/controllers/webhook.js b/packages/server/src/api/controllers/webhook.js index 67427e5710..1698775ab4 100644 --- a/packages/server/src/api/controllers/webhook.js +++ b/packages/server/src/api/controllers/webhook.js @@ -54,7 +54,7 @@ exports.destroy = async ctx => { } exports.buildSchema = async ctx => { - updateAppId(ctx.params.instance) + await updateAppId(ctx.params.instance) const db = getAppDB() const webhook = await db.get(ctx.params.id) webhook.bodySchema = toJsonSchema(ctx.request.body) @@ -80,7 +80,7 @@ exports.buildSchema = async ctx => { exports.trigger = async ctx => { const prodAppId = getProdAppID(ctx.params.instance) - updateAppId(prodAppId) + await updateAppId(prodAppId) try { const db = getAppDB() const webhook = await db.get(ctx.params.id) diff --git a/packages/server/src/api/routes/tests/misc.spec.js b/packages/server/src/api/routes/tests/misc.spec.js index 475176759c..21dba8f085 100644 --- a/packages/server/src/api/routes/tests/misc.spec.js +++ b/packages/server/src/api/routes/tests/misc.spec.js @@ -43,53 +43,55 @@ describe("run misc tests", () => { describe("test table utilities", () => { it("should be able to import a CSV", async () => { - const table = await config.createTable({ - name: "table", - type: "table", - key: "name", - schema: { - a: { - type: "string", - constraints: { + return config.doInContext(null, async () => { + const table = await config.createTable({ + name: "table", + type: "table", + key: "name", + schema: { + a: { type: "string", + constraints: { + type: "string", + }, + }, + b: { + type: "string", + constraints: { + type: "string", + }, + }, + c: { + type: "string", + constraints: { + type: "string", + }, + }, + d: { + type: "string", + constraints: { + type: "string", + }, }, }, - b: { - type: "string", - constraints: { - type: "string", - }, - }, - c: { - type: "string", - constraints: { - type: "string", - }, - }, - d: { - type: "string", - constraints: { - type: "string", - }, - }, - }, + }) + const dataImport = { + csvString: "a,b,c,d\n1,2,3,4", + schema: {}, + } + for (let col of ["a", "b", "c", "d"]) { + dataImport.schema[col] = { type: "string" } + } + await tableUtils.handleDataImport( + { userId: "test" }, + table, + dataImport + ) + const rows = await config.getRows() + expect(rows[0].a).toEqual("1") + expect(rows[0].b).toEqual("2") + expect(rows[0].c).toEqual("3") }) - const dataImport = { - csvString: "a,b,c,d\n1,2,3,4", - schema: {}, - } - for (let col of ["a", "b", "c", "d"]) { - dataImport.schema[col] = { type: "string" } - } - await tableUtils.handleDataImport( - { userId: "test" }, - table, - dataImport - ) - const rows = await config.getRows() - expect(rows[0].a).toEqual("1") - expect(rows[0].b).toEqual("2") - expect(rows[0].c).toEqual("3") }) }) }) \ No newline at end of file diff --git a/packages/server/src/api/routes/tests/row.spec.js b/packages/server/src/api/routes/tests/row.spec.js index 8354f01ad7..d7ec995edb 100644 --- a/packages/server/src/api/routes/tests/row.spec.js +++ b/packages/server/src/api/routes/tests/row.spec.js @@ -2,6 +2,7 @@ const { outputProcessing } = require("../../../utilities/rowProcessor") const setup = require("./utilities") const { basicRow } = setup.structures const { doInAppContext } = require("@budibase/backend-core/context") +const { doInTenant } = require("@budibase/backend-core/tenancy") // mock the fetch for the search system jest.mock("node-fetch") @@ -340,17 +341,20 @@ describe("/rows", () => { describe("fetchEnrichedRows", () => { it("should allow enriching some linked rows", async () => { - const table = await config.createLinkedTable() - const firstRow = await config.createRow({ - name: "Test Contact", - description: "original description", - tableId: table._id - }) - const secondRow = await config.createRow({ - name: "Test 2", - description: "og desc", - link: [{_id: firstRow._id}], - tableId: table._id, + const { table, firstRow, secondRow } = await doInTenant(setup.structures.TENANT_ID, async () => { + const table = await config.createLinkedTable() + const firstRow = await config.createRow({ + name: "Test Contact", + description: "original description", + tableId: table._id + }) + const secondRow = await config.createRow({ + name: "Test 2", + description: "og desc", + link: [{_id: firstRow._id}], + tableId: table._id, + }) + return { table, firstRow, secondRow } }) // test basic enrichment diff --git a/packages/server/src/api/routes/tests/table.spec.js b/packages/server/src/api/routes/tests/table.spec.js index 794e35e040..e10e908572 100644 --- a/packages/server/src/api/routes/tests/table.spec.js +++ b/packages/server/src/api/routes/tests/table.spec.js @@ -1,4 +1,5 @@ -const { checkBuilderEndpoint, getDB } = require("./utilities/TestFunctions") +const { checkBuilderEndpoint } = require("./utilities/TestFunctions") +const { getAppDB } = require("@budibase/backend-core/context") const setup = require("./utilities") const { basicTable } = setup.structures @@ -122,7 +123,7 @@ describe("/tables", () => { describe("indexing", () => { it("should be able to create a table with indexes", async () => { - const db = getDB(config) + const db = getAppDB(config) const indexCount = (await db.getIndexes()).total_rows const table = basicTable() table.indexes = ["name"] diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts index c86a980d2c..a34527e8f2 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.ts +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.ts @@ -2,6 +2,7 @@ import * as rowController from "../../../controllers/row" import * as appController from "../../../controllers/application" import { AppStatus } from "../../../../db/utils" import { BUILTIN_ROLE_IDS } from "@budibase/backend-core/roles" +import { doInTenant } from "@budibase/backend-core/tenancy" import { TENANT_ID } from "../../../../tests/utilities/structures" import { getAppDB, doInAppContext } from "@budibase/backend-core/context" import * as env from "../../../../environment" @@ -32,17 +33,19 @@ export const getAllTableRows = async (config: any) => { } export const clearAllApps = async (tenantId = TENANT_ID) => { - const req: any = { query: { status: AppStatus.DEV }, user: { tenantId } } - await appController.fetch(req) - const apps = req.body - if (!apps || apps.length <= 0) { - return - } - for (let app of apps) { - const { appId } = app - const req = new Request(null, { appId }) - await runRequest(appId, appController.destroy, req) - } + await doInTenant(tenantId, async () => { + const req: any = { query: { status: AppStatus.DEV }, user: { tenantId } } + await appController.fetch(req) + const apps = req.body + if (!apps || apps.length <= 0) { + return + } + for (let app of apps) { + const { appId } = app + const req = new Request(null, { appId }) + await runRequest(appId, appController.destroy, req) + } + }) } export const clearAllAutomations = async (config: any) => { diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index 1189d8cee3..8efc383194 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -1,8 +1,8 @@ // need to load environment first import { ExtendableContext } from "koa" import * as env from "./environment" -const CouchDB = require("./db") -require("@budibase/backend-core").init(CouchDB) +import db from "./db" +db.init() const Koa = require("koa") const destroyable = require("server-destroy") const koaBody = require("koa-body") diff --git a/packages/server/src/automations/steps/bash.js b/packages/server/src/automations/steps/bash.js index 1d3c22fd0e..efa4295e35 100644 --- a/packages/server/src/automations/steps/bash.js +++ b/packages/server/src/automations/steps/bash.js @@ -1,6 +1,7 @@ const { execSync } = require("child_process") const { processStringSync } = require("@budibase/string-templates") const automationUtils = require("../automationUtils") +const environment = require("../../environment") exports.definition = { name: "Bash Scripting", @@ -51,7 +52,9 @@ exports.run = async function ({ inputs, context }) { let stdout, success = true try { - stdout = execSync(command, { timeout: 500 }).toString() + stdout = execSync(command, { + timeout: environment.QUERY_THREAD_TIMEOUT || 500, + }).toString() } catch (err) { stdout = err.message success = false diff --git a/packages/server/src/automations/tests/deleteRow.spec.ts b/packages/server/src/automations/tests/deleteRow.spec.ts index 5766fd58bc..a96aa7329f 100644 --- a/packages/server/src/automations/tests/deleteRow.spec.ts +++ b/packages/server/src/automations/tests/deleteRow.spec.ts @@ -26,7 +26,7 @@ describe("test the delete row action", () => { expect(res.row._id).toEqual(row._id) let error try { - await config.getRow(table._id, res.id) + await config.getRow(table._id, res.row._id) } catch (err) { error = err } diff --git a/packages/server/src/automations/tests/utilities/index.js b/packages/server/src/automations/tests/utilities/index.js index 9fcb9a9cdf..b2e1566687 100644 --- a/packages/server/src/automations/tests/utilities/index.js +++ b/packages/server/src/automations/tests/utilities/index.js @@ -1,4 +1,6 @@ const TestConfig = require("../../../tests/utilities/TestConfiguration") +const { TENANT_ID } = require("../../../tests/utilities/structures") +const { doInTenant } = require("@budibase/backend-core/tenancy") const actions = require("../../actions") const emitter = require("../../../events/index") const env = require("../../../environment") @@ -31,14 +33,16 @@ exports.runInProd = async fn => { } exports.runStep = async function runStep(stepId, inputs) { - let step = await actions.getAction(stepId) - expect(step).toBeDefined() - return step({ - inputs, - appId: config ? config.getAppId() : null, - // don't really need an API key, mocked out usage quota, not being tested here - apiKey: exports.apiKey, - emitter, + return doInTenant(TENANT_ID, async () => { + let step = await actions.getAction(stepId) + expect(step).toBeDefined() + return step({ + inputs, + appId: config ? config.getAppId() : null, + // don't really need an API key, mocked out usage quota, not being tested here + apiKey: exports.apiKey, + emitter, + }) }) } diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts index 21e0e64f6d..1f86abc5b9 100644 --- a/packages/server/src/automations/utils.ts +++ b/packages/server/src/automations/utils.ts @@ -1,12 +1,11 @@ import { Thread, ThreadType } from "../threads" import { definitions } from "./triggerInfo" import * as webhooks from "../api/controllers/webhook" -import CouchDB from "../db" import { queue } from "./bullboard" import newid from "../db/newid" import { updateEntityMetadata } from "../utilities" import { MetadataTypes, WebhookType } from "../constants" -import { getProdAppID } from "@budibase/backend-core/db" +import { getProdAppID, doWithDB } from "@budibase/backend-core/db" import { cloneDeep } from "lodash/fp" import { getAppDB, getAppId } from "@budibase/backend-core/context" import { tenancy } from "@budibase/backend-core" @@ -113,10 +112,11 @@ export async function enableCronTrigger(appId: any, automation: any) { // can't use getAppDB here as this is likely to be called from dev app, // but this call could be for dev app or prod app, need to just use what // was passed in - const db = new CouchDB(appId) - const response = await db.put(automation) - automation._id = response.id - automation._rev = response.rev + await doWithDB(appId, async (db: any) => { + const response = await db.put(automation) + automation._id = response.id + automation._rev = response.rev + }) } return automation } diff --git a/packages/server/src/db/client.js b/packages/server/src/db/client.js deleted file mode 100644 index 9e90163fff..0000000000 --- a/packages/server/src/db/client.js +++ /dev/null @@ -1,31 +0,0 @@ -const PouchDB = require("pouchdb") -const { getCouchUrl } = require("@budibase/backend-core/db") -const replicationStream = require("pouchdb-replication-stream") -const allDbs = require("pouchdb-all-dbs") -const find = require("pouchdb-find") -const env = require("../environment") - -const COUCH_DB_URL = getCouchUrl() || "http://localhost:4005" - -PouchDB.plugin(replicationStream.plugin) -PouchDB.plugin(find) -PouchDB.adapter("writableStream", replicationStream.adapters.writableStream) - -let POUCH_DB_DEFAULTS = { - prefix: COUCH_DB_URL, -} - -if (env.isTest()) { - PouchDB.plugin(require("pouchdb-adapter-memory")) - POUCH_DB_DEFAULTS = { - prefix: undefined, - adapter: "memory", - } -} - -const Pouch = PouchDB.defaults(POUCH_DB_DEFAULTS) - -// have to still have pouch alldbs for testing -allDbs(Pouch) - -module.exports = Pouch diff --git a/packages/server/src/db/inMemoryView.js b/packages/server/src/db/inMemoryView.js index 892617e068..ec99b4738c 100644 --- a/packages/server/src/db/inMemoryView.js +++ b/packages/server/src/db/inMemoryView.js @@ -1,48 +1,49 @@ -const PouchDB = require("pouchdb") -const memory = require("pouchdb-adapter-memory") const newid = require("./newid") -PouchDB.plugin(memory) -const Pouch = PouchDB.defaults({ - prefix: undefined, - adapter: "memory", -}) +// bypass the main application db config +// use in memory pouchdb directly +const { getPouch, closeDB } = require("@budibase/backend-core/db") +const Pouch = getPouch({ inMemory: true }) exports.runView = async (view, calculation, group, data) => { // use a different ID each time for the DB, make sure they // are always unique for each query, don't want overlap // which could cause 409s const db = new Pouch(newid()) - // write all the docs to the in memory Pouch (remove revs) - await db.bulkDocs( - data.map(row => ({ - ...row, - _rev: undefined, - })) - ) - let fn = (doc, emit) => emit(doc._id) - eval("fn = " + view.map.replace("function (doc)", "function (doc, emit)")) - const queryFns = { - meta: view.meta, - map: fn, - } - if (view.reduce) { - queryFns.reduce = view.reduce - } - const response = await db.query(queryFns, { - include_docs: !calculation, - group: !!group, - }) - // need to fix the revs to be totally accurate - for (let row of response.rows) { - if (!row._rev || !row._id) { - continue + try { + // write all the docs to the in memory Pouch (remove revs) + await db.bulkDocs( + data.map(row => ({ + ...row, + _rev: undefined, + })) + ) + let fn = (doc, emit) => emit(doc._id) + eval("fn = " + view.map.replace("function (doc)", "function (doc, emit)")) + const queryFns = { + meta: view.meta, + map: fn, } - const found = data.find(possible => possible._id === row._id) - if (found) { - row._rev = found._rev + if (view.reduce) { + queryFns.reduce = view.reduce } + const response = await db.query(queryFns, { + include_docs: !calculation, + group: !!group, + }) + // need to fix the revs to be totally accurate + for (let row of response.rows) { + if (!row._rev || !row._id) { + continue + } + const found = data.find(possible => possible._id === row._id) + if (found) { + row._rev = found._rev + } + } + return response + } finally { + await db.destroy() + await closeDB(db) } - await db.destroy() - return response } diff --git a/packages/server/src/db/index.js b/packages/server/src/db/index.js index f03b5b1fb0..75ad19b87f 100644 --- a/packages/server/src/db/index.js +++ b/packages/server/src/db/index.js @@ -1,3 +1,16 @@ -const client = require("./client") +const core = require("@budibase/backend-core") +const env = require("../environment") -module.exports = client +exports.init = () => { + const dbConfig = { + replication: true, + find: true, + } + + if (env.isTest()) { + dbConfig.inMemory = true + dbConfig.allDbs = true + } + + core.init({ db: dbConfig }) +} diff --git a/packages/server/src/db/tests/linkTests.spec.js b/packages/server/src/db/tests/linkTests.spec.js index 9a309df70a..8bc26cde2a 100644 --- a/packages/server/src/db/tests/linkTests.spec.js +++ b/packages/server/src/db/tests/linkTests.spec.js @@ -1,8 +1,8 @@ const TestConfig = require("../../tests/utilities/TestConfiguration") const { basicTable } = require("../../tests/utilities/structures") const linkUtils = require("../linkedRows/linkUtils") -const CouchDB = require("../index") const { getAppDB } = require("@budibase/backend-core/context") +const { doWithDB } = require("@budibase/backend-core/db") describe("test link functionality", () => { const config = new TestConfig(false) @@ -48,12 +48,13 @@ describe("test link functionality", () => { describe("getLinkDocuments", () => { it("should create the link view when it doesn't exist", async () => { // create the DB and a very basic app design DB - const db = new CouchDB("test") - await db.put({ _id: "_design/database", views: {} }) - const output = await linkUtils.getLinkDocuments({ - tableId: "test", - rowId: "test", - includeDocs: false, + const output = await doWithDB("test", async db => { + await db.put({ _id: "_design/database", views: {} }) + return await linkUtils.getLinkDocuments({ + tableId: "test", + rowId: "test", + includeDocs: false, + }) }) expect(Array.isArray(output)).toBe(true) }) diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js index 6a45a04b1d..ff1061dbaf 100644 --- a/packages/server/src/environment.js +++ b/packages/server/src/environment.js @@ -24,6 +24,12 @@ if (!LOADED && isDev() && !isTest()) { LOADED = true } +function parseIntSafe(number) { + if (number) { + return parseInt(number) + } +} + let inThread = false module.exports = { @@ -61,6 +67,7 @@ module.exports = { SENDGRID_API_KEY: process.env.SENDGRID_API_KEY, DYNAMO_ENDPOINT: process.env.DYNAMO_ENDPOINT, POSTHOG_TOKEN: process.env.POSTHOG_TOKEN, + QUERY_THREAD_TIMEOUT: parseIntSafe(process.env.QUERY_THREAD_TIMEOUT), // old - to remove CLIENT_ID: process.env.CLIENT_ID, BUDIBASE_DIR: process.env.BUDIBASE_DIR, @@ -70,7 +77,6 @@ module.exports = { DEPLOYMENT_CREDENTIALS_URL: process.env.DEPLOYMENT_CREDENTIALS_URL, ALLOW_DEV_AUTOMATIONS: process.env.ALLOW_DEV_AUTOMATIONS, DISABLE_THREADING: process.env.DISABLE_THREADING, - QUERY_THREAD_TIMEOUT: process.env.QUERY_THREAD_TIMEOUT, SQL_MAX_ROWS: process.env.SQL_MAX_ROWS, _set(key, value) { process.env[key] = value diff --git a/packages/server/src/integrations/couchdb.ts b/packages/server/src/integrations/couchdb.ts index 0405a319ea..ea7edb6136 100644 --- a/packages/server/src/integrations/couchdb.ts +++ b/packages/server/src/integrations/couchdb.ts @@ -53,51 +53,55 @@ module CouchDBModule { class CouchDBIntegration implements IntegrationBase { private config: CouchDBConfig - private client: any + private readonly client: any constructor(config: CouchDBConfig) { this.config = config this.client = new PouchDB(`${config.url}/${config.database}`) } - async create(query: { json: object }) { + async query( + command: string, + errorMsg: string, + query: { json?: object; id?: string } + ) { try { - return this.client.post(query.json) + const response = await this.client[command](query.id || query.json) + await this.client.close() + return response } catch (err) { - console.error("Error writing to couchDB", err) + console.error(errorMsg, err) throw err } } + async create(query: { json: object }) { + return this.query("post", "Error writing to couchDB", query) + } + async read(query: { json: object }) { - try { - const result = await this.client.allDocs({ + const result = await this.query("allDocs", "Error querying couchDB", { + json: { include_docs: true, ...query.json, - }) - return result.rows.map((row: { doc: object }) => row.doc) - } catch (err) { - console.error("Error querying couchDB", err) - throw err - } + }, + }) + return result.rows.map((row: { doc: object }) => row.doc) } async update(query: { json: object }) { - try { - return this.client.put(query.json) - } catch (err) { - console.error("Error updating couchDB document", err) - throw err - } + return this.query("put", "Error updating couchDB document", query) } async delete(query: { id: string }) { - try { - return await this.client.remove(query.id) - } catch (err) { - console.error("Error deleting couchDB document", err) - throw err - } + const doc = await this.query( + "get", + "Cannot find doc to be deleted", + query + ) + return this.query("remove", "Error deleting couchDB document", { + json: doc, + }) } } diff --git a/packages/server/src/integrations/dynamodb.ts b/packages/server/src/integrations/dynamodb.ts index be3668a08a..9ce4201a1e 100644 --- a/packages/server/src/integrations/dynamodb.ts +++ b/packages/server/src/integrations/dynamodb.ts @@ -131,11 +131,12 @@ module DynamoModule { constructor(config: DynamoDBConfig) { this.config = config - if (!this.config.endpoint) { + if (this.config.endpoint && !this.config.endpoint.includes("localhost")) { this.connect() } let options = { correctClockSkew: true, + region: this.config.region || AWS_REGION, endpoint: config.endpoint ? config.endpoint : undefined, } this.client = new AWS.DynamoDB.DocumentClient(options) diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts index c58fdea551..e6d79bfdde 100644 --- a/packages/server/src/integrations/googlesheets.ts +++ b/packages/server/src/integrations/googlesheets.ts @@ -16,6 +16,7 @@ module GoogleSheetsModule { const { getGlobalDB } = require("@budibase/backend-core/tenancy") const { getScopedConfig } = require("@budibase/backend-core/db") const { Configs } = require("@budibase/backend-core/constants") + const fetch = require("node-fetch") interface GoogleSheetsConfig { spreadsheetId: string @@ -28,6 +29,16 @@ module GoogleSheetsModule { refreshToken: string } + interface AuthTokenRequest { + client_id: string + client_secret: string + refresh_token: string + } + + interface AuthTokenResponse { + access_token: string + } + const SCHEMA: Integration = { plus: true, auth: { @@ -40,6 +51,7 @@ module GoogleSheetsModule { friendlyName: "Google Sheets", datasource: { spreadsheetId: { + display: "Google Sheet URL", type: DatasourceFieldTypes.STRING, required: true, }, @@ -135,6 +147,30 @@ module GoogleSheetsModule { return parts.length > 5 ? parts[5] : spreadsheetId } + async fetchAccessToken( + payload: AuthTokenRequest + ): Promise { + const response = await fetch( + "https://www.googleapis.com/oauth2/v4/token", + { + method: "POST", + body: JSON.stringify({ + ...payload, + grant_type: "refresh_token", + }), + headers: { + "Content-Type": "application/json", + }, + } + ) + + if (response.status !== 200) { + throw new Error("Error authenticating with google sheets.") + } + + return response.json() + } + async connect() { try { // Initialise oAuth client @@ -154,14 +190,18 @@ module GoogleSheetsModule { clientId: googleConfig.clientID, clientSecret: googleConfig.clientSecret, }) - oauthClient.on("tokens", tokens => { - oauthClient.setCredentials({ - refresh_token: googleConfig.refreshToken, - access_token: tokens.access_token, - }) + + const tokenResponse = await this.fetchAccessToken({ + client_id: googleConfig.clientID, + client_secret: googleConfig.clientSecret, + refresh_token: this.config.auth.refreshToken, }) - oauthClient.credentials.access_token = this.config.auth.accessToken - oauthClient.credentials.refresh_token = this.config.auth.refreshToken + + oauthClient.setCredentials({ + refresh_token: this.config.auth.refreshToken, + access_token: tokenResponse.access_token, + }) + this.client.useOAuth2Client(oauthClient) await this.client.loadInfo() } catch (err) { diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts index cd5dc77f9b..065a1b2333 100644 --- a/packages/server/src/integrations/mysql.ts +++ b/packages/server/src/integrations/mysql.ts @@ -15,6 +15,7 @@ import { } from "./utils" import { DatasourcePlus } from "./base/datasourcePlus" import dayjs from "dayjs" +const { NUMBER_REGEX } = require("../utilities") module MySQLModule { const mysql = require("mysql2/promise") @@ -26,7 +27,8 @@ module MySQLModule { user: string password: string database: string - ssl?: object + ssl?: { [key: string]: any } + rejectUnauthorized: boolean } const SCHEMA: Integration = { @@ -64,6 +66,11 @@ module MySQLModule { type: DatasourceFieldTypes.OBJECT, required: false, }, + rejectUnauthorized: { + type: DatasourceFieldTypes.BOOLEAN, + default: true, + required: false, + }, }, query: { create: { @@ -87,7 +94,7 @@ module MySQLModule { if (typeof binding !== "string") { continue } - const matches = binding.match(/^\d*$/g) + const matches = binding.match(NUMBER_REGEX) // check if number first if (matches && matches[0] !== "" && !isNaN(Number(matches[0]))) { bindings[i] = parseFloat(binding) @@ -113,6 +120,16 @@ module MySQLModule { if (config.ssl && Object.keys(config.ssl).length === 0) { delete config.ssl } + // make sure this defaults to true + if ( + config.rejectUnauthorized != null && + !config.rejectUnauthorized && + config.ssl + ) { + config.ssl.rejectUnauthorized = config.rejectUnauthorized + } + // @ts-ignore + delete config.rejectUnauthorized this.config = config } diff --git a/packages/server/src/integrations/queries/sql.ts b/packages/server/src/integrations/queries/sql.ts new file mode 100644 index 0000000000..cf71f2ee2a --- /dev/null +++ b/packages/server/src/integrations/queries/sql.ts @@ -0,0 +1,125 @@ +import { findHBSBlocks, processStringSync } from "@budibase/string-templates" +import { Integration } from "../../definitions/datasource" +import { DatasourcePlus } from "../base/datasourcePlus" + +const CONST_CHAR_REGEX = new RegExp("'[^']*'", "g") + +export function enrichQueryFields( + fields: { [key: string]: any }, + parameters = {} +) { + const enrichedQuery: { [key: string]: any } = Array.isArray(fields) ? [] : {} + + // enrich the fields with dynamic parameters + for (let key of Object.keys(fields)) { + if (fields[key] == null) { + continue + } + if (typeof fields[key] === "object") { + // enrich nested fields object + enrichedQuery[key] = enrichQueryFields(fields[key], parameters) + } else if (typeof fields[key] === "string") { + // enrich string value as normal + enrichedQuery[key] = processStringSync(fields[key], parameters, { + noEscaping: true, + noHelpers: true, + escapeNewlines: true, + }) + } else { + enrichedQuery[key] = fields[key] + } + } + if ( + enrichedQuery.json || + enrichedQuery.customData || + enrichedQuery.requestBody + ) { + try { + enrichedQuery.json = JSON.parse( + enrichedQuery.json || + enrichedQuery.customData || + enrichedQuery.requestBody + ) + } catch (err) { + // no json found, ignore + } + delete enrichedQuery.customData + } + return enrichedQuery +} + +export function interpolateSQL( + fields: { [key: string]: any }, + parameters: { [key: string]: any }, + integration: DatasourcePlus +) { + let sql = fields.sql + if (!sql || typeof sql !== "string") { + return fields + } + const bindings = findHBSBlocks(sql) + let variables = [], + arrays = [] + for (let binding of bindings) { + // look for array/list operations in the SQL statement, which will need handled later + const listRegexMatch = sql.match( + new RegExp(`(in|IN|In|iN)( )+[(]?${binding}[)]?`) + ) + // check if the variable was used as part of a string concat e.g. 'Hello {{binding}}' + // start by finding all the instances of const character strings + const charConstMatch = sql.match(CONST_CHAR_REGEX) || [] + // now look within them to see if a binding is used + const charConstBindingMatch = charConstMatch.find((string: any) => + string.match(new RegExp(`'[^']*${binding}[^']*'`)) + ) + if (charConstBindingMatch) { + let [part1, part2] = charConstBindingMatch.split(binding) + part1 = `'${part1.substring(1)}'` + part2 = `'${part2.substring(0, part2.length - 1)}'` + sql = sql.replace( + charConstBindingMatch, + integration.getStringConcat([ + part1, + integration.getBindingIdentifier(), + part2, + ]) + ) + } + // generate SQL parameterised array + else if (listRegexMatch) { + arrays.push(binding) + // determine the length of the array + const value = enrichQueryFields([binding], parameters)[0] + .split(",") + .map((val: string) => val.trim()) + // build a string like ($1, $2, $3) + let replacement = `${Array.apply(null, Array(value.length)) + .map(() => integration.getBindingIdentifier()) + .join(",")}` + // check if parentheses are needed + if (!listRegexMatch[0].includes(`(${binding})`)) { + replacement = `(${replacement})` + } + sql = sql.replace(binding, replacement) + } else { + sql = sql.replace(binding, integration.getBindingIdentifier()) + } + variables.push(binding) + } + // replicate the knex structure + fields.sql = sql + fields.bindings = enrichQueryFields(variables, parameters) + // check for arrays in the data + let updated: string[] = [] + for (let i = 0; i < variables.length; i++) { + if (arrays.includes(variables[i])) { + updated = updated.concat( + fields.bindings[i].split(",").map((val: string) => val.trim()) + ) + } else { + updated.push(fields.bindings[i]) + } + } + fields.bindings = updated + return fields +} diff --git a/packages/server/src/integrations/tests/airtable.spec.js b/packages/server/src/integrations/tests/airtable.spec.js index e6654f6f71..4769430ded 100644 --- a/packages/server/src/integrations/tests/airtable.spec.js +++ b/packages/server/src/integrations/tests/airtable.spec.js @@ -7,7 +7,9 @@ class TestConfiguration { this.integration = new AirtableIntegration.integration(config) this.client = { create: jest.fn(), - select: jest.fn(), + select: jest.fn(() => ({ + firstPage: jest.fn(() => []), + })), update: jest.fn(), destroy: jest.fn(), } diff --git a/packages/server/src/integrations/tests/couchdb.spec.js b/packages/server/src/integrations/tests/couchdb.spec.js index e21b67fa1c..65c9c83ad2 100644 --- a/packages/server/src/integrations/tests/couchdb.spec.js +++ b/packages/server/src/integrations/tests/couchdb.spec.js @@ -2,8 +2,10 @@ jest.mock("pouchdb", () => function CouchDBMock() { this.post = jest.fn() this.allDocs = jest.fn(() => ({ rows: [] })) this.put = jest.fn() + this.get = jest.fn() this.remove = jest.fn() this.plugin = jest.fn() + this.close = jest.fn() }) const CouchDBIntegration = require("../couchdb") @@ -62,6 +64,7 @@ describe("CouchDB Integration", () => { it("calls the delete method with the correct params", async () => { const id = "1234" const response = await config.integration.delete({ id }) - expect(config.integration.client.remove).toHaveBeenCalledWith(id) + expect(config.integration.client.get).toHaveBeenCalledWith(id) + expect(config.integration.client.remove).toHaveBeenCalled() }) }) \ No newline at end of file diff --git a/packages/server/src/middleware/builder.js b/packages/server/src/middleware/builder.js index a6404780ff..f4568722c1 100644 --- a/packages/server/src/middleware/builder.js +++ b/packages/server/src/middleware/builder.js @@ -5,7 +5,7 @@ const { checkDebounce, setDebounce, } = require("../utilities/redis") -const { getDB } = require("@budibase/backend-core/db") +const { doWithDB } = require("@budibase/backend-core/db") const { DocumentTypes } = require("../db/utils") const { PermissionTypes } = require("@budibase/backend-core/permissions") const { app: appCache } = require("@budibase/backend-core/cache") @@ -48,14 +48,15 @@ async function updateAppUpdatedAt(ctx) { if (ctx.method === "GET" || (await checkDebounce(appId))) { return } - const db = getDB(appId) - const metadata = await db.get(DocumentTypes.APP_METADATA) - metadata.updatedAt = new Date().toISOString() - const response = await db.put(metadata) - metadata._rev = response.rev - await appCache.invalidateAppMetadata(appId, metadata) - // set a new debounce record with a short TTL - await setDebounce(appId, DEBOUNCE_TIME_SEC) + await doWithDB(appId, async db => { + const metadata = await db.get(DocumentTypes.APP_METADATA) + metadata.updatedAt = new Date().toISOString() + const response = await db.put(metadata) + metadata._rev = response.rev + await appCache.invalidateAppMetadata(appId, metadata) + // set a new debounce record with a short TTL + await setDebounce(appId, DEBOUNCE_TIME_SEC) + }) } module.exports = async (ctx, permType) => { diff --git a/packages/server/src/middleware/tests/authorized.spec.js b/packages/server/src/middleware/tests/authorized.spec.js index cf15b28458..f23eb6206b 100644 --- a/packages/server/src/middleware/tests/authorized.spec.js +++ b/packages/server/src/middleware/tests/authorized.spec.js @@ -10,7 +10,6 @@ jest.mock("../../environment", () => ({ const authorizedMiddleware = require("../authorized") const env = require("../../environment") const { PermissionTypes, PermissionLevels } = require("@budibase/backend-core/permissions") -require("@budibase/backend-core").init(require("../../db")) const { doInAppContext } = require("@budibase/backend-core/context") const APP_ID = "" diff --git a/packages/server/src/migrations/functions/tests/appUrls.spec.js b/packages/server/src/migrations/functions/tests/appUrls.spec.js index d3f080dfd4..fe5b9aeeae 100644 --- a/packages/server/src/migrations/functions/tests/appUrls.spec.js +++ b/packages/server/src/migrations/functions/tests/appUrls.spec.js @@ -1,12 +1,10 @@ -const { DocumentTypes } = require("@budibase/backend-core/db") -const env = require("../../../environment") +const { DocumentTypes, doWithDB } = require("@budibase/backend-core/db") const TestConfig = require("../../../tests/utilities/TestConfiguration") const migration = require("../appUrls") describe("run", () => { let config = new TestConfig(false) - const CouchDB = config.getCouch() beforeEach(async () => { await config.init() @@ -16,14 +14,13 @@ describe("run", () => { it("runs successfully", async () => { const app = await config.createApp("testApp") - const appDb = new CouchDB(app.appId) - let metadata = await appDb.get(DocumentTypes.APP_METADATA) - delete metadata.url - await appDb.put(metadata) - - await migration.run(appDb) - - metadata = await appDb.get(DocumentTypes.APP_METADATA) + const metadata = await doWithDB(app.appId, async db => { + const metadataDoc = await db.get(DocumentTypes.APP_METADATA) + delete metadataDoc.url + await db.put(metadataDoc) + await migration.run(db) + return await db.get(DocumentTypes.APP_METADATA) + }) expect(metadata.url).toEqual("/testapp") }) }) diff --git a/packages/server/src/migrations/functions/tests/userEmailViewCasing.spec.js b/packages/server/src/migrations/functions/tests/userEmailViewCasing.spec.js index c0d7823cbf..9db59caa4a 100644 --- a/packages/server/src/migrations/functions/tests/userEmailViewCasing.spec.js +++ b/packages/server/src/migrations/functions/tests/userEmailViewCasing.spec.js @@ -1,5 +1,6 @@ const TestConfig = require("../../../tests/utilities/TestConfiguration") -const { getGlobalDB } = require("@budibase/backend-core/tenancy") +const { TENANT_ID } = require("../../../tests/utilities/structures") +const { getGlobalDB, doInTenant } = require("@budibase/backend-core/tenancy") // mock email view creation const coreDb = require("@budibase/backend-core/db") @@ -9,17 +10,19 @@ coreDb.createUserEmailView = createUserEmailView const migration = require("../userEmailViewCasing") describe("run", () => { - let config = new TestConfig(false) - const globalDb = getGlobalDB() + doInTenant(TENANT_ID, () => { + let config = new TestConfig(false) + const globalDb = getGlobalDB() - beforeEach(async () => { - await config.init() - }) + beforeEach(async () => { + await config.init() + }) - afterAll(config.end) + afterAll(config.end) - it("runs successfully", async () => { - await migration.run(globalDb) - expect(createUserEmailView).toHaveBeenCalledTimes(1) + it("runs successfully", async () => { + await migration.run(globalDb) + expect(createUserEmailView).toHaveBeenCalledTimes(1) + }) }) }) diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts index f07b8aa431..dbc978b9bd 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncApps.spec.ts @@ -12,21 +12,23 @@ describe("syncApps", () => { afterAll(config.end) it("runs successfully", async () => { - // create the usage quota doc and mock usages - await quotas.getQuotaUsage() - await quotas.setUsage(3, StaticQuotaName.APPS, QuotaUsageType.STATIC) + return config.doInContext(null, async () => { + // create the usage quota doc and mock usages + await quotas.getQuotaUsage() + await quotas.setUsage(3, StaticQuotaName.APPS, QuotaUsageType.STATIC) - let usageDoc = await quotas.getQuotaUsage() - expect(usageDoc.usageQuota.apps).toEqual(3) + let usageDoc = await quotas.getQuotaUsage() + expect(usageDoc.usageQuota.apps).toEqual(3) - // create an extra app to test the migration - await config.createApp("quota-test") + // create an extra app to test the migration + await config.createApp("quota-test") - // migrate - await syncApps.run() + // migrate + await syncApps.run() - // assert the migration worked - usageDoc = await quotas.getQuotaUsage() - expect(usageDoc.usageQuota.apps).toEqual(2) + // assert the migration worked + usageDoc = await quotas.getQuotaUsage() + expect(usageDoc.usageQuota.apps).toEqual(2) + }) }) }) diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts index 8bcd5df332..851deb5417 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts @@ -12,27 +12,29 @@ describe("syncRows", () => { afterAll(config.end) it("runs successfully", async () => { - // create the usage quota doc and mock usages - await quotas.getQuotaUsage() - await quotas.setUsage(300, StaticQuotaName.ROWS, QuotaUsageType.STATIC) + return config.doInContext(null, async () => { + // create the usage quota doc and mock usages + await quotas.getQuotaUsage() + await quotas.setUsage(300, StaticQuotaName.ROWS, QuotaUsageType.STATIC) - let usageDoc = await quotas.getQuotaUsage() - expect(usageDoc.usageQuota.rows).toEqual(300) + let usageDoc = await quotas.getQuotaUsage() + expect(usageDoc.usageQuota.rows).toEqual(300) - // app 1 - await config.createTable() - await config.createRow() - // app 2 - await config.createApp("second-app") - await config.createTable() - await config.createRow() - await config.createRow() + // app 1 + await config.createTable() + await config.createRow() + // app 2 + await config.createApp("second-app") + await config.createTable() + await config.createRow() + await config.createRow() - // migrate - await syncRows.run() + // migrate + await syncRows.run() - // assert the migration worked - usageDoc = await quotas.getQuotaUsage() - expect(usageDoc.usageQuota.rows).toEqual(3) + // assert the migration worked + usageDoc = await quotas.getQuotaUsage() + expect(usageDoc.usageQuota.rows).toEqual(3) + }) }) }) diff --git a/packages/server/src/migrations/index.ts b/packages/server/src/migrations/index.ts index d8383fcb39..6d63d81544 100644 --- a/packages/server/src/migrations/index.ts +++ b/packages/server/src/migrations/index.ts @@ -1,4 +1,3 @@ -import CouchDB from "../db" const { MIGRATION_TYPES, runMigrations, @@ -64,5 +63,5 @@ export const MIGRATIONS: Migration[] = [ ] export const migrate = async (options?: MigrationOptions) => { - await runMigrations(CouchDB, MIGRATIONS, options) + await runMigrations(MIGRATIONS, options) } diff --git a/packages/server/src/module.d.ts b/packages/server/src/module.d.ts index 0d1dc8d938..0419a40a14 100644 --- a/packages/server/src/module.d.ts +++ b/packages/server/src/module.d.ts @@ -5,3 +5,7 @@ declare module "@budibase/backend-core/context" declare module "@budibase/backend-core/cache" declare module "@budibase/backend-core/permissions" declare module "@budibase/backend-core/roles" +declare module "@budibase/backend-core/constants" +declare module "@budibase/backend-core/auth" +declare module "@budibase/backend-core/sessions" +declare module "@budibase/backend-core/encryption" diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js index 6ebafa8421..fbf0f17abd 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.js +++ b/packages/server/src/tests/utilities/TestConfiguration.js @@ -1,6 +1,4 @@ -const core = require("@budibase/backend-core") -const CouchDB = require("../../db") -core.init(CouchDB) +require("../../db").init() const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles") const env = require("../../environment") const { @@ -20,7 +18,7 @@ const supertest = require("supertest") const { cleanup } = require("../../utilities/fileSystem") const { Cookies, Headers } = require("@budibase/backend-core/constants") const { jwt } = require("@budibase/backend-core/auth") -const { getGlobalDB } = require("@budibase/backend-core/tenancy") +const { doInTenant, doWithGlobalDB } = require("@budibase/backend-core/tenancy") const { createASession } = require("@budibase/backend-core/sessions") const { user: userCache } = require("@budibase/backend-core/cache") const newid = require("../../db/newid") @@ -57,8 +55,20 @@ class TestConfiguration { return this.appId } - getCouch() { - return CouchDB + async doInContext(appId, task) { + if (!appId) { + appId = this.appId + } + return doInTenant(TENANT_ID, () => { + // check if already in a context + if (context.getAppId() == null && appId !== null) { + return context.doInAppContext(appId, async () => { + return task() + }) + } else { + return task() + } + }) } async _req(config, params, controlFunc) { @@ -72,35 +82,28 @@ class TestConfiguration { request.request = { body: config, } - async function run() { + return this.doInContext(this.appId, async () => { if (params) { request.params = params } await controlFunc(request) return request.body - } - // check if already in a context - if (context.getAppId() == null && this.appId !== null) { - return context.doInAppContext(this.appId, async () => { - return run() - }) - } else { - return run() - } + }) } async generateApiKey(userId = GLOBAL_USER_ID) { - const db = getGlobalDB(TENANT_ID) - const id = generateDevInfoID(userId) - let devInfo - try { - devInfo = await db.get(id) - } catch (err) { - devInfo = { _id: id, userId } - } - devInfo.apiKey = encrypt(`${TENANT_ID}${SEPARATOR}${newid()}`) - await db.put(devInfo) - return devInfo.apiKey + return doWithGlobalDB(TENANT_ID, async db => { + const id = generateDevInfoID(userId) + let devInfo + try { + devInfo = await db.get(id) + } catch (err) { + devInfo = { _id: id, userId } + } + devInfo.apiKey = encrypt(`${TENANT_ID}${SEPARATOR}${newid()}`) + await db.put(devInfo) + return devInfo.apiKey + }) } async globalUser({ @@ -109,34 +112,35 @@ class TestConfiguration { email = EMAIL, roles, } = {}) { - const db = getGlobalDB(TENANT_ID) - let existing - try { - existing = await db.get(id) - } catch (err) { - existing = { email } - } - const user = { - _id: id, - ...existing, - roles: roles || {}, - tenantId: TENANT_ID, - } - await createASession(id, { - sessionId: "sessionid", - tenantId: TENANT_ID, - csrfToken: CSRF_TOKEN, + return doWithGlobalDB(TENANT_ID, async db => { + let existing + try { + existing = await db.get(id) + } catch (err) { + existing = { email } + } + const user = { + _id: id, + ...existing, + roles: roles || {}, + tenantId: TENANT_ID, + } + await createASession(id, { + sessionId: "sessionid", + tenantId: TENANT_ID, + csrfToken: CSRF_TOKEN, + }) + if (builder) { + user.builder = { global: true } + } else { + user.builder = { global: false } + } + const resp = await db.put(user) + return { + _rev: resp._rev, + ...user, + } }) - if (builder) { - user.builder = { global: true } - } else { - user.builder = { global: false } - } - const resp = await db.put(user) - return { - _rev: resp._rev, - ...user, - } } // use a new id as the name to avoid name collisions @@ -205,9 +209,12 @@ class TestConfiguration { async createApp(appName) { // create dev app + // clear any old app + this.appId = null + await context.updateAppId(null) this.app = await this._req({ name: appName }, null, controllers.app.create) this.appId = this.app.appId - context.updateAppId(this.appId) + await context.updateAppId(this.appId) // create production app this.prodApp = await this.deploy() diff --git a/packages/server/src/threads/index.ts b/packages/server/src/threads/index.ts index a6a1cb1ad9..c19453cf44 100644 --- a/packages/server/src/threads/index.ts +++ b/packages/server/src/threads/index.ts @@ -26,6 +26,7 @@ export class Thread { count: any disableThreading: any workers: any + timeoutMs: any constructor(type: any, opts: any = { timeoutMs: null, count: 1 }) { this.type = type @@ -41,6 +42,7 @@ export class Thread { maxConcurrentWorkers: this.count, } if (opts.timeoutMs) { + this.timeoutMs = opts.timeoutMs workerOpts.maxCallTime = opts.timeoutMs } this.workers = workerFarm(workerOpts, typeToFile(type)) @@ -57,7 +59,13 @@ export class Thread { fncToCall = this.workers } fncToCall(data, (err: any, response: any) => { - if (err) { + 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.js index 270c2cc713..71994a7244 100644 --- a/packages/server/src/threads/query.js +++ b/packages/server/src/threads/query.js @@ -2,12 +2,13 @@ const threadUtils = require("./utils") threadUtils.threadSetup() const ScriptRunner = require("../utilities/scriptRunner") const { integrations } = require("../integrations") -const { - processStringSync, - findHBSBlocks, -} = require("@budibase/string-templates") +const { processStringSync } = require("@budibase/string-templates") const { doInAppContext, getAppDB } = require("@budibase/backend-core/context") const { isSQL } = require("../integrations/utils") +const { + enrichQueryFields, + interpolateSQL, +} = require("../integrations/queries/sql") class QueryRunner { constructor(input, flags = { noRecursiveQuery: false }) { @@ -27,69 +28,6 @@ class QueryRunner { this.hasRerun = false } - interpolateSQL(fields, parameters, integration) { - let sql = fields.sql - if (!sql) { - return fields - } - const bindings = findHBSBlocks(sql) - let variables = [], - arrays = [] - for (let binding of bindings) { - // look for array/list operations in the SQL statement, which will need handled later - const listRegex = new RegExp(`(in|IN|In|iN)( )+${binding}`) - const listRegexMatch = sql.match(listRegex) - // check if the variable was used as part of a string concat e.g. 'Hello {{binding}}' - const charConstRegex = new RegExp(`'[^']*${binding}[^']*'`) - const charConstMatch = sql.match(charConstRegex) - if (charConstMatch) { - let [part1, part2] = charConstMatch[0].split(binding) - part1 = `'${part1.substring(1)}'` - part2 = `'${part2.substring(0, part2.length - 1)}'` - sql = sql.replace( - charConstMatch[0], - integration.getStringConcat([ - part1, - integration.getBindingIdentifier(), - part2, - ]) - ) - } - // generate SQL parameterised array - else if (listRegexMatch) { - arrays.push(binding) - // determine the length of the array - const value = this.enrichQueryFields([binding], parameters)[0].split( - "," - ) - // build a string like ($1, $2, $3) - sql = sql.replace( - binding, - `(${Array.apply(null, Array(value.length)) - .map(() => integration.getBindingIdentifier()) - .join(",")})` - ) - } else { - sql = sql.replace(binding, integration.getBindingIdentifier()) - } - variables.push(binding) - } - // replicate the knex structure - fields.sql = sql - fields.bindings = this.enrichQueryFields(variables, parameters) - // check for arrays in the data - let updated = [] - for (let i = 0; i < variables.length; i++) { - if (arrays.includes(variables[i])) { - updated = updated.concat(fields.bindings[i].split(",")) - } else { - updated.push(fields.bindings[i]) - } - } - fields.bindings = updated - return fields - } - async execute() { let { datasource, fields, queryVerb, transformer } = this const Integration = integrations[datasource.source] @@ -103,9 +41,9 @@ class QueryRunner { let query // handle SQL injections by interpolating the variables if (isSQL(datasource)) { - query = this.interpolateSQL(fields, parameters, integration) + query = interpolateSQL(fields, parameters, integration) } else { - query = this.enrichQueryFields(fields, parameters) + query = enrichQueryFields(fields, parameters) } // Add pagination values for REST queries @@ -250,47 +188,6 @@ class QueryRunner { } return parameters } - - enrichQueryFields(fields, parameters = {}) { - const enrichedQuery = Array.isArray(fields) ? [] : {} - - // enrich the fields with dynamic parameters - for (let key of Object.keys(fields)) { - if (fields[key] == null) { - continue - } - if (typeof fields[key] === "object") { - // enrich nested fields object - enrichedQuery[key] = this.enrichQueryFields(fields[key], parameters) - } else if (typeof fields[key] === "string") { - // enrich string value as normal - enrichedQuery[key] = processStringSync(fields[key], parameters, { - noEscaping: true, - noHelpers: true, - escapeNewlines: true, - }) - } else { - enrichedQuery[key] = fields[key] - } - } - if ( - enrichedQuery.json || - enrichedQuery.customData || - enrichedQuery.requestBody - ) { - try { - enrichedQuery.json = JSON.parse( - enrichedQuery.json || - enrichedQuery.customData || - enrichedQuery.requestBody - ) - } catch (err) { - // no json found, ignore - } - delete enrichedQuery.customData - } - return enrichedQuery - } } module.exports = (input, callback) => { diff --git a/packages/server/src/threads/utils.js b/packages/server/src/threads/utils.js index 5d8dc115e5..77824eba96 100644 --- a/packages/server/src/threads/utils.js +++ b/packages/server/src/threads/utils.js @@ -1,6 +1,5 @@ const env = require("../environment") -const CouchDB = require("../db") -const { init } = require("@budibase/backend-core") +const db = require("../db") const redis = require("@budibase/backend-core/redis") const { SEPARATOR } = require("@budibase/backend-core/db") @@ -25,7 +24,7 @@ exports.threadSetup = () => { } // when thread starts, make sure it is recorded env.setInThread() - init(CouchDB) + db.init() } function makeVariableKey(queryId, variable) { diff --git a/packages/server/src/utilities/fileSystem/index.js b/packages/server/src/utilities/fileSystem/index.js index 904b4ced18..8a02afc5b3 100644 --- a/packages/server/src/utilities/fileSystem/index.js +++ b/packages/server/src/utilities/fileSystem/index.js @@ -2,7 +2,7 @@ const { budibaseTempDir } = require("../budibaseDir") const fs = require("fs") const { join } = require("path") const uuid = require("uuid/v4") -const CouchDB = require("../../db") +const { doWithDB } = require("@budibase/backend-core/db") const { ObjectStoreBuckets } = require("../../constants") const { upload, @@ -151,41 +151,41 @@ exports.streamBackup = async appId => { * @return {*} either a readable stream or a string */ exports.exportDB = async (dbName, { stream, filter, exportName } = {}) => { - const instanceDb = new CouchDB(dbName) - - // Stream the dump if required - if (stream) { - const memStream = new MemoryStream() - instanceDb.dump(memStream, { filter }) - return memStream - } - - // Write the dump to file if required - if (exportName) { - const path = join(budibaseTempDir(), exportName) - const writeStream = fs.createWriteStream(path) - await instanceDb.dump(writeStream, { filter }) - - // Upload the dump to the object store if self hosted - if (env.SELF_HOSTED) { - await streamUpload( - ObjectStoreBuckets.BACKUPS, - join(dbName, exportName), - fs.createReadStream(path) - ) + return doWithDB(dbName, async db => { + // Stream the dump if required + if (stream) { + const memStream = new MemoryStream() + db.dump(memStream, { filter }) + return memStream } - return fs.createReadStream(path) - } + // Write the dump to file if required + if (exportName) { + const path = join(budibaseTempDir(), exportName) + const writeStream = fs.createWriteStream(path) + await db.dump(writeStream, { filter }) - // Stringify the dump in memory if required - const memStream = new MemoryStream() - let appString = "" - memStream.on("data", chunk => { - appString += chunk.toString() + // Upload the dump to the object store if self hosted + if (env.SELF_HOSTED) { + await streamUpload( + ObjectStoreBuckets.BACKUPS, + join(dbName, exportName), + fs.createReadStream(path) + ) + } + + return fs.createReadStream(path) + } + + // Stringify the dump in memory if required + const memStream = new MemoryStream() + let appString = "" + memStream.on("data", chunk => { + appString += chunk.toString() + }) + await db.dump(memStream, { filter }) + return appString }) - await instanceDb.dump(memStream, { filter }) - return appString } /** diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js index 221c2ff18b..66005fd9cd 100644 --- a/packages/server/src/utilities/index.js +++ b/packages/server/src/utilities/index.js @@ -11,6 +11,8 @@ exports.wait = ms => new Promise(resolve => setTimeout(resolve, ms)) exports.isDev = env.isDev +exports.NUMBER_REGEX = /^[+-]?([0-9]*[.])?[0-9]+$/g + exports.removeFromArray = (array, element) => { const index = array.indexOf(element) if (index !== -1) { diff --git a/packages/server/src/utilities/usageQuota/rows.js b/packages/server/src/utilities/usageQuota/rows.js index 378caffc46..78879cc166 100644 --- a/packages/server/src/utilities/usageQuota/rows.js +++ b/packages/server/src/utilities/usageQuota/rows.js @@ -1,6 +1,9 @@ const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils") -const CouchDB = require("../../db") -const { isDevAppID, getDevelopmentAppID } = require("@budibase/backend-core/db") +const { + isDevAppID, + getDevelopmentAppID, + doWithDB, +} = require("@budibase/backend-core/db") const ROW_EXCLUSIONS = [USER_METDATA_PREFIX] @@ -24,22 +27,23 @@ const getAppPairs = appIds => { const getAppRows = async appId => { // need to specify the app ID, as this is used for different apps in one call - const appDb = new CouchDB(appId) - const response = await appDb.allDocs( - getRowParams(null, null, { - include_docs: false, - }) - ) - return response.rows - .map(r => r.id) - .filter(id => { - for (let exclusion of ROW_EXCLUSIONS) { - if (id.startsWith(exclusion)) { - return false + return doWithDB(appId, async db => { + const response = await db.allDocs( + getRowParams(null, null, { + include_docs: false, + }) + ) + return response.rows + .map(r => r.id) + .filter(id => { + for (let exclusion of ROW_EXCLUSIONS) { + if (id.startsWith(exclusion)) { + return false + } } - } - return true - }) + return true + }) + }) } /** @@ -58,7 +62,7 @@ exports.getUniqueRows = async appIds => { continue } try { - appRows.push(await getAppRows(appId)) + appRows = appRows.concat(await getAppRows(appId)) } catch (e) { console.error(e) // don't error out if we can't count the app rows, just continue diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 4537e7efb8..13cedfadb5 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1014,10 +1014,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@1.0.105-alpha.40": - version "1.0.105-alpha.40" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.105-alpha.40.tgz#7e8e3c548d09001a002364d2a9fa4dabf2d1bcce" - integrity sha512-lOUJx5yFAcBld+SNwbO1hUV2ucM2J+Y4AIG0BQeNH2kPul74sHlZpEocbmNu+R88NgKinTLcnB0wCdoD0MP+4g== +"@budibase/backend-core@1.0.105-alpha.42": + version "1.0.105-alpha.42" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.105-alpha.42.tgz#732daf9234312261c91158303459bb02f95656e0" + integrity sha512-takLU6UcUVVzcF8EZEazxmY37Th8DwjG8CEtBrlYZn+yrAO+27XixOws72P+6Xr9IxGyAWxMpIQ8E5uZi6Zl9w== dependencies: "@techpass/passport-openidconnect" "^0.3.0" aws-sdk "^2.901.0" @@ -1087,12 +1087,12 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" -"@budibase/pro@1.0.105-alpha.40": - version "1.0.105-alpha.40" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.105-alpha.40.tgz#155952a2645b547cb974a3c1bccb17f3075849e2" - integrity sha512-qrd7vxBkLcLoxWVtakg1P8M7NZUVM5d/ROveUsS1pDAVQndiI8fVrc7YeOfIiHmqdaFQXbwp9tn6ZviMuihVsA== +"@budibase/pro@1.0.105-alpha.42": + version "1.0.105-alpha.42" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.105-alpha.42.tgz#b616b24d9008c268f87b532b89493670d5a0a915" + integrity sha512-ibiJRm+22B4t8XZVkDQz8RU8Jd3XSS0M0K8vLRqdFaB632Vt/dnnMx6GbUvurjSfqxsa72R2+jNOME64oUl0Gg== dependencies: - "@budibase/backend-core" "1.0.105-alpha.40" + "@budibase/backend-core" "1.0.105-alpha.42" node-fetch "^2.6.1" "@budibase/standard-components@^0.9.139": @@ -2179,9 +2179,9 @@ integrity sha512-aJmhAK6S8O6ePKF6ohfTcB3UiTi6Mpxi4L1z6/4M9y66ci+KcZsHXX7tyWmGfZsirx/QjaacESqQVbqHD0PJ5g== "@spectrum-css/illustratedmessage@^3.0.2": - version "3.0.13" - resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.13.tgz#6cb2132f7b7c6077ccbde820bcb792c4c31df32f" - integrity sha512-pKWtWRoVOEP5LTsMPqbuoxfy8/mFlNkoj+cO7l0AgPFSqzJZcljjuHIKHc6Y8NvLpx6g2OfjD7e44oo3INyROg== + version "3.0.8" + resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.8.tgz#69ef0c935bcc5027f233a78de5aeb0064bf033cb" + integrity sha512-HvC4dywDi11GdrXQDCvKQ0vFlrXLTyJuc9UKf7meQLCGoJbGYDBwe+tHXNK1c6gPMD9BoL6pPMP1K/vRzR4EBQ== "@spectrum-css/inputgroup@^3.0.2": version "3.0.8" @@ -2276,9 +2276,9 @@ integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg== "@spectrum-css/tabs@^3.0.1": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.2.tgz#a847daeec41f6272c567639b56d41b10f5bb67e6" - integrity sha512-5W6ET+JJcloMMeNjluycrm0Cq5f/p+n55V+MZsaSlJKDpApvOu6sZf9SKTiISmpysuKRHFx5LiE+2EjviSi6Bg== + version "3.1.5" + resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.1.5.tgz#cc82e69c1fc721902345178231fb95d05938b983" + integrity sha512-UtfW8bA1quYnJM6v/lp6AVYGnQFkiUix2FHAf/4VHVrk4mh7ydtLiXS0IR3Kx+t/S8FWdSdSQHDZ8tHbY1ZLZg== "@spectrum-css/tags@^3.0.2": version "3.0.3" @@ -3026,14 +3026,6 @@ abstract-leveldown@~2.7.1: dependencies: xtend "~4.0.0" -abstract-leveldown@~6.0.0: - version "6.0.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.0.3.tgz#b4b6159343c74b0c5197b2817854782d8f748c4a" - integrity sha512-jzewKKpZbaYUa6HTThnrl+GrJhzjEAeuc7hTVpZdzg7kupXZFoqQDFwyOwLNbmJKJlmzw8yiipMPkDiuKkT06Q== - dependencies: - level-concat-iterator "~2.0.0" - xtend "~4.0.0" - abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: version "6.2.3" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" @@ -3496,9 +3488,9 @@ aws-sdk@^2.767.0: xml2js "0.4.19" aws-sdk@^2.901.0: - version "2.1118.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1118.0.tgz#1789e881b1f43bef7807111d5716ab691ab965c2" - integrity sha512-R3g06c4RC0Gz/lwMA7wgC7+FwYf5vaO30sPIigoX5m6Tfb7tdzfCYD7pnpvkPRNUvWJ3f5kQk+pEeW25DstRrQ== + version "2.1121.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1121.0.tgz#381510f7216f1d177b01620612f60014fa48e562" + integrity sha512-SEbPk0cFxiqhx8s2n9ozPafWyoIH944fg8Tpy9AxqZlq/tSCphWNE0CgKATnNAKoltWdVHBTKeLwnOAK/7OX7A== dependencies: buffer "4.9.2" events "1.1.1" @@ -3916,21 +3908,21 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= -buffer-from@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" - integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== - 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.0.0: +buffer-from@1.1.2: 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== +buffer-from@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== + buffer-writer@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" @@ -4804,14 +4796,6 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== -deferred-leveldown@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.1.0.tgz#c21e40641a8e48530255a4ad31371cc7fe76b332" - integrity sha512-PvDY+BT2ONu2XVRgxHb77hYelLtMYxKSGuWuJJdVRXh9ntqx9GYTFJno/SKAz5xcd+yjQwyQeIZrUPjPvA52mg== - dependencies: - abstract-leveldown "~6.0.0" - inherits "^2.0.3" - deferred-leveldown@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" @@ -5234,11 +5218,6 @@ es3ify@^0.2.2: jstransform "~11.0.0" through "~2.3.4" -es6-denodeify@^0.1.1: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f" - integrity sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8= - es6-error@^4.0.1, es6-error@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" @@ -5865,13 +5844,12 @@ fetch-cookie@0.10.1: dependencies: tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" -fetch-cookie@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.7.3.tgz#b8d023f421dd2b2f4a0eca9cd7318a967ed4eed8" - integrity sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA== +fetch-cookie@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== dependencies: - es6-denodeify "^0.1.1" - tough-cookie "^2.3.3" + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" figures@^3.0.0: version "3.2.0" @@ -6844,16 +6822,16 @@ image-q@^1.1.1: resolved "https://registry.yarnpkg.com/image-q/-/image-q-1.1.1.tgz#fc84099664460b90ca862d9300b6bfbbbfbf8056" integrity sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY= -immediate@3.0.6, immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= - immediate@3.3.0, immediate@^3.2.3: version "3.3.0" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + import-fresh@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -8861,18 +8839,18 @@ left-pad@^1.3.0: resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== -level-codec@9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.1.tgz#042f4aa85e56d4328ace368c950811ba802b7247" - integrity sha512-ajFP0kJ+nyq4i6kptSM+mAvJKLOg1X5FiFPtLG9M5gCEZyBmgDi3FkDrvlMkEzrUn1cWxtvVmrvoS4ASyO/q+Q== - -level-codec@9.0.2, level-codec@^9.0.0: +level-codec@9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== dependencies: buffer "^5.6.0" +level-codec@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.1.tgz#042f4aa85e56d4328ace368c950811ba802b7247" + integrity sha512-ajFP0kJ+nyq4i6kptSM+mAvJKLOg1X5FiFPtLG9M5gCEZyBmgDi3FkDrvlMkEzrUn1cWxtvVmrvoS4ASyO/q+Q== + level-concat-iterator@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" @@ -8926,26 +8904,16 @@ level-write-stream@1.0.0: dependencies: end-stream "~0.1.0" -level@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/level/-/level-6.0.0.tgz#d216fb9b9c3940bcec15c5880d8da775ca086c5c" - integrity sha512-3oAi7gXLLNr7pHj8c4vbI6lHkXf35m8qb7zWMrNTrOax6CXBVggQAwL1xnC/1CszyYrW3BsLXsY5TMgTxtKfFA== +level@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/level/-/level-6.0.1.tgz#dc34c5edb81846a6de5079eac15706334b0d7cd6" + integrity sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw== dependencies: level-js "^5.0.0" level-packager "^5.1.0" leveldown "^5.4.0" - opencollective-postinstall "^2.0.0" -leveldown@5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.4.1.tgz#83a8fdd9bb52b1ed69be2ef59822b6cdfcdb51ec" - integrity sha512-3lMPc7eU3yj5g+qF1qlALInzIYnkySIosR1AsUKFjL9D8fYbTLuENBAeDRZXIG4qeWOAyqRItOoLu2v2avWiMA== - dependencies: - abstract-leveldown "~6.2.1" - napi-macros "~2.0.0" - node-gyp-build "~4.1.0" - -leveldown@^5.4.0: +leveldown@5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98" integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== @@ -8954,15 +8922,14 @@ leveldown@^5.4.0: napi-macros "~2.0.0" node-gyp-build "~4.1.0" -levelup@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.1.0.tgz#49ab5d3a341731cd102f91c6bc17a1acb1969a17" - integrity sha512-+Qhe2/jb5affN7BeFgWUUWVdYoGXO2nFS3QLEZKZynnQyP9xqA+7wgOz3fD8SST2UKpHQuZgjyJjTcB2nMl2dQ== +leveldown@^5.4.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.4.1.tgz#83a8fdd9bb52b1ed69be2ef59822b6cdfcdb51ec" + integrity sha512-3lMPc7eU3yj5g+qF1qlALInzIYnkySIosR1AsUKFjL9D8fYbTLuENBAeDRZXIG4qeWOAyqRItOoLu2v2avWiMA== dependencies: - deferred-leveldown "~5.1.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - xtend "~4.0.0" + 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" @@ -9674,11 +9641,6 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.4.1.tgz#b2e38f1117b8acbedbe0524f041fb3177188255d" - integrity sha512-P9UbpFK87NyqBZzUuDBDz4f6Yiys8xm8j7ACDbi6usvFm6KItklQUKjeoqTrYS/S1k6I8oaOC2YLLDr/gg26Mw== - node-fetch@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -9993,11 +9955,6 @@ openapi-validator@^0.14.2: path-parser "^6.1.0" typeof "^1.0.0" -opencollective-postinstall@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== - optionator@^0.8.1, optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -10765,30 +10722,30 @@ pouchdb-utils@7.2.2: pouchdb-md5 "7.2.2" uuid "8.1.0" -pouchdb@7.2.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-7.2.1.tgz#619e3d5c2463ddd94a4b1bf40d44408c46e9de79" - integrity sha512-AoDPdr6tFqj3xs7oiD2oioYj5MMu87c3UemRHZ/p++BwU+ZsKn5jpnL09OvWTLvMvaICGAOufiaUzmM1/KKoKQ== +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.0" + buffer-from "1.1.2" clone-buffer "1.0.0" double-ended-queue "2.1.0-0" - fetch-cookie "0.7.3" - immediate "3.0.6" + fetch-cookie "0.11.0" + immediate "3.3.0" inherits "2.0.4" - level "6.0.0" - level-codec "9.0.1" + level "6.0.1" + level-codec "9.0.2" level-write-stream "1.0.0" - leveldown "5.4.1" - levelup "4.1.0" + leveldown "5.6.0" + levelup "4.4.0" ltgt "2.2.1" - node-fetch "2.4.1" - readable-stream "1.0.33" - spark-md5 "3.0.0" - through2 "3.0.1" - uuid "3.3.3" + 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" prelude-ls@~1.1.2: @@ -11082,16 +11039,6 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@1.0.33: - version "1.0.33" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.33.tgz#3a360dd66c1b1d7fd4705389860eda1d0f61126c" - integrity sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readable-stream@1.1.14, readable-stream@^1.0.27-1: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" @@ -11929,16 +11876,16 @@ source-map@^0.7.3, source-map@~0.7.2: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -spark-md5@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.0.tgz#3722227c54e2faf24b1dc6d933cc144e6f71bfef" - integrity sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8= - 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.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== + sparse-bitfield@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" @@ -12351,9 +12298,9 @@ svelte-portal@^1.0.0: integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== 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.44.1" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.44.1.tgz#5cc772a8340f4519a4ecd1ac1a842325466b1a63" + integrity sha512-4DrCEJoBvdR689efHNSxIQn2pnFwB7E7j2yLEJtHE/P8hxwZWIphCtJ8are7bjl/iVMlcEf5uh5pJ68IwR09vQ== svg.draggable.js@^2.2.2: version "2.2.2" @@ -12598,13 +12545,6 @@ throat@^6.0.1: resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== -through2@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" - integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== - dependencies: - readable-stream "2 || 3" - through2@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" @@ -13164,27 +13104,17 @@ utils-merge@1.x.x: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@3.3.2: +uuid@3.3.2, uuid@^3.1.0, 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@3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== - 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@^3.1.0, 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== - -uuid@^8.3.0, uuid@^8.3.2: +uuid@8.3.2, uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 2d68722f81..777133fe93 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 29439fe149..40cc8197c7 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "1.0.105-alpha.45", + "version": "1.0.122", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -31,9 +31,9 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "^1.0.105-alpha.45", - "@budibase/pro": "1.0.105-alpha.45", - "@budibase/string-templates": "^1.0.105-alpha.45", + "@budibase/backend-core": "^1.0.122", + "@budibase/string-templates": "^1.0.122", + "@budibase/pro": "1.0.105-alpha.43", "@koa/router": "^8.0.0", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "^0.3.0", @@ -58,7 +58,7 @@ "passport-jwt": "^4.0.0", "passport-local": "^1.0.0", "pino-pretty": "^4.0.0", - "pouchdb": "^7.2.1", + "pouchdb": "7.3.0", "pouchdb-all-dbs": "^1.0.2", "server-destroy": "^1.0.1" }, diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index d13b08f94c..441a1f15ab 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -11,6 +11,7 @@ const { invalidateSessions } = require("@budibase/backend-core/sessions") const accounts = require("@budibase/backend-core/accounts") const { getGlobalDB, + doWithGlobalDB, getTenantId, getTenantUser, doesTenantExist, @@ -49,26 +50,27 @@ export const adminUser = async (ctx: any) => { ctx.throw(403, "Organisation already exists.") } - const db = getGlobalDB(tenantId) - const response = await db.allDocs( - getGlobalUserParams(null, { - include_docs: true, - }) - ) - - // write usage quotas for cloud - if (!env.SELF_HOSTED) { - // could be a scenario where it exists, make sure its clean - try { - const usageQuota = await db.get(StaticDatabases.GLOBAL.docs.usageQuota) - if (usageQuota) { - await db.remove(usageQuota._id, usageQuota._rev) + const response = await doWithGlobalDB(tenantId, async (db: any) => { + const response = await db.allDocs( + getGlobalUserParams(null, { + include_docs: true, + }) + ) + // write usage quotas for cloud + if (!env.SELF_HOSTED) { + // could be a scenario where it exists, make sure its clean + try { + const usageQuota = await db.get(StaticDatabases.GLOBAL.docs.usageQuota) + if (usageQuota) { + await db.remove(usageQuota._id, usageQuota._rev) + } + } catch (err) { + // don't worry about errors } - } catch (err) { - // don't worry about errors + await db.put(quotas.generateNewQuotaUsage()) } - await db.put(quotas.generateNewQuotaUsage()) - } + return response + }) if (response.rows.some((row: any) => row.doc.admin)) { ctx.throw( diff --git a/packages/worker/src/api/controllers/system/tenants.js b/packages/worker/src/api/controllers/system/tenants.js index 4d41ce894c..8c0e3c5bfd 100644 --- a/packages/worker/src/api/controllers/system/tenants.js +++ b/packages/worker/src/api/controllers/system/tenants.js @@ -1,37 +1,42 @@ -const CouchDB = require("../../../db") -const { StaticDatabases } = require("@budibase/backend-core/db") +const { StaticDatabases, doWithDB } = require("@budibase/backend-core/db") const { getTenantId } = require("@budibase/backend-core/tenancy") const { deleteTenant } = require("@budibase/backend-core/deprovision") exports.exists = async ctx => { const tenantId = ctx.request.params - const db = new CouchDB(StaticDatabases.PLATFORM_INFO.name) - let exists = false - try { - const tenantsDoc = await db.get(StaticDatabases.PLATFORM_INFO.docs.tenants) - if (tenantsDoc) { - exists = tenantsDoc.tenantIds.indexOf(tenantId) !== -1 - } - } catch (err) { - // if error it doesn't exist - } ctx.body = { - exists, + exists: await doWithDB(StaticDatabases.PLATFORM_INFO.name, async db => { + let exists = false + try { + const tenantsDoc = await db.get( + StaticDatabases.PLATFORM_INFO.docs.tenants + ) + if (tenantsDoc) { + exists = tenantsDoc.tenantIds.indexOf(tenantId) !== -1 + } + } catch (err) { + // if error it doesn't exist + } + return exists + }), } } exports.fetch = async ctx => { - const db = new CouchDB(StaticDatabases.PLATFORM_INFO.name) - let tenants = [] - try { - const tenantsDoc = await db.get(StaticDatabases.PLATFORM_INFO.docs.tenants) - if (tenantsDoc) { - tenants = tenantsDoc.tenantIds + ctx.body = await doWithDB(StaticDatabases.PLATFORM_INFO.name, async db => { + let tenants = [] + try { + const tenantsDoc = await db.get( + StaticDatabases.PLATFORM_INFO.docs.tenants + ) + if (tenantsDoc) { + tenants = tenantsDoc.tenantIds + } + } catch (err) { + // if error it doesn't exist } - } catch (err) { - // if error it doesn't exist - } - ctx.body = tenants + return tenants + }) } exports.delete = async ctx => { diff --git a/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js b/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js index 6b6c0e24b3..d297d818bd 100644 --- a/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js +++ b/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js @@ -1,3 +1,4 @@ +require("../../../../db").init() const env = require("../../../../environment") const controllers = require("./controllers") const supertest = require("supertest") @@ -8,15 +9,12 @@ const { getGlobalUserByEmail } = require("@budibase/backend-core/utils") const { createASession } = require("@budibase/backend-core/sessions") const { newid } = require("@budibase/backend-core/src/hashing") const { TENANT_ID, CSRF_TOKEN } = require("./structures") -const core = require("@budibase/backend-core") -const CouchDB = require("../../../../db") const { doInTenant } = require("@budibase/backend-core/tenancy") -core.init(CouchDB) class TestConfiguration { constructor(openServer = true) { if (openServer) { - env.PORT = 4003 + env.PORT = 4012 this.server = require("../../../../index") // we need the request for logging in, involves cookies, hard to fake this.request = supertest(this.server) diff --git a/packages/worker/src/db/index.js b/packages/worker/src/db/index.js index 770aabd95b..25dc02962b 100644 --- a/packages/worker/src/db/index.js +++ b/packages/worker/src/db/index.js @@ -1,26 +1,11 @@ -const PouchDB = require("pouchdb") -const allDbs = require("pouchdb-all-dbs") +const core = require("@budibase/backend-core") const env = require("../environment") -const { getCouchUrl } = require("@budibase/backend-core/db") -// level option is purely for testing (development) -const COUCH_DB_URL = getCouchUrl() || "http://localhost:4005" - -let POUCH_DB_DEFAULTS = { - prefix: COUCH_DB_URL, -} - -if (env.isTest()) { - PouchDB.plugin(require("pouchdb-adapter-memory")) - POUCH_DB_DEFAULTS = { - prefix: undefined, - adapter: "memory", +exports.init = () => { + const dbConfig = {} + if (env.isTest()) { + dbConfig.inMemory = true + dbConfig.allDbs = true } + core.init({ db: dbConfig }) } - -const Pouch = PouchDB.defaults(POUCH_DB_DEFAULTS) - -// have to still have pouch alldbs for testing -allDbs(Pouch) - -module.exports = Pouch diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index f89a38bc7a..1cec2868c6 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -5,8 +5,8 @@ import Application from "koa" import { bootstrap } from "global-agent" const env = require("./environment") -const CouchDB = require("./db") -require("@budibase/backend-core").init(CouchDB) +import db from "./db" +db.init() const Koa = require("koa") const destroyable = require("server-destroy") const koaBody = require("koa-body") diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 59cb73118a..d6174fb8aa 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -286,10 +286,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@1.0.105-alpha.38": - version "1.0.105-alpha.38" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.105-alpha.38.tgz#399bc37877392f04c0072936d1c74d35d2997d6c" - integrity sha512-IKVw3+a42Yea49Qc8vbVd+KZzOIAfgAFEohApJZSxqKA5UaFeWPJ343LQ7oC6jbYOkRVlGRnkrvXXa1jRggqbA== +"@budibase/backend-core@1.0.105-alpha.42": + version "1.0.105-alpha.42" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.105-alpha.42.tgz#732daf9234312261c91158303459bb02f95656e0" + integrity sha512-takLU6UcUVVzcF8EZEazxmY37Th8DwjG8CEtBrlYZn+yrAO+27XixOws72P+6Xr9IxGyAWxMpIQ8E5uZi6Zl9w== dependencies: "@techpass/passport-openidconnect" "^0.3.0" aws-sdk "^2.901.0" @@ -310,12 +310,12 @@ uuid "^8.3.2" zlib "^1.0.5" -"@budibase/pro@1.0.105-alpha.38": - version "1.0.105-alpha.38" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.105-alpha.38.tgz#f025daf5667798083a7b0af301d6231dc3e58f00" - integrity sha512-TXSov/c2KT7YuxZRspSd4iNPZPiJOdpl91ZTxGrqaPfK8PDmgk/XBWkHci+z1WLCvf6YY2kuQJGp1moldoLO1g== +"@budibase/pro@1.0.105-alpha.42": + version "1.0.105-alpha.42" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.105-alpha.42.tgz#b616b24d9008c268f87b532b89493670d5a0a915" + integrity sha512-ibiJRm+22B4t8XZVkDQz8RU8Jd3XSS0M0K8vLRqdFaB632Vt/dnnMx6GbUvurjSfqxsa72R2+jNOME64oUl0Gg== dependencies: - "@budibase/backend-core" "1.0.105-alpha.38" + "@budibase/backend-core" "1.0.105-alpha.42" node-fetch "^2.6.1" "@cspotcode/source-map-consumer@0.8.0": @@ -1524,7 +1524,7 @@ buffer-from@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.0.0: +buffer-from@1.1.2, buffer-from@^1.0.0: 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== @@ -2578,10 +2578,10 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -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== +fetch-cookie@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== dependencies: tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" @@ -4432,9 +4432,9 @@ mimic-response@^3.1.0: brace-expansion "^1.1.7" minimist@^1.2.0, minimist@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== mkdirp-classic@^0.5.2: version "0.5.3" @@ -4493,12 +4493,7 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -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-fetch@^2.6.1: +node-fetch@2.6.7, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -5026,17 +5021,17 @@ pouchdb-utils@7.2.2: pouchdb-md5 "7.2.2" uuid "8.1.0" -pouchdb@^7.2.1: - version "7.2.2" - resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-7.2.2.tgz#fcae82862db527e4cf7576ed8549d1384961f364" - integrity sha512-5gf5nw5XH/2H/DJj8b0YkvG9fhA/4Jt6kL0Y8QjtztVjb1y4J19Rg4rG+fUbXu96gsUrlyIvZ3XfM0b4mogGmw== +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.1" + buffer-from "1.1.2" clone-buffer "1.0.0" double-ended-queue "2.1.0-0" - fetch-cookie "0.10.1" + fetch-cookie "0.11.0" immediate "3.3.0" inherits "2.0.4" level "6.0.1" @@ -5045,11 +5040,11 @@ pouchdb@^7.2.1: leveldown "5.6.0" levelup "4.4.0" ltgt "2.2.1" - node-fetch "2.6.0" + node-fetch "2.6.7" readable-stream "1.1.14" - spark-md5 "3.0.1" + spark-md5 "3.0.2" through2 "3.0.2" - uuid "8.1.0" + uuid "8.3.2" vuvuzela "1.0.3" prelude-ls@~1.1.2: @@ -5671,6 +5666,11 @@ spark-md5@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.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== + split2@^3.1.1: version "3.2.2" resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" @@ -6225,9 +6225,9 @@ uri-js@^4.2.2: punycode "^2.1.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== + version "1.19.8" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.8.tgz#ee0407a18528934d3c383e691912f47043a58feb" + integrity sha512-iIXHrjomQ0ZCuDRy44wRbyTZVnfVNLVo3Ksz1yxNyE5wV1IDZW2S5Jszy45DTlw/UdsnRT7DyDhIz7Gy+vJumw== url-parse-lax@^3.0.0: version "3.0.0" @@ -6264,16 +6264,16 @@ uuid@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" + 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== -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - 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"