-{#if $backendUiStore.selectedDatabase.id}
+{#if $backendUiStore.selectedDatabase._id}
{/if}
diff --git a/packages/builder/src/pages/[application]/backend/database/_layout.svelte b/packages/builder/src/pages/[application]/backend/database/_layout.svelte
index 6a5792ad3..94453e394 100644
--- a/packages/builder/src/pages/[application]/backend/database/_layout.svelte
+++ b/packages/builder/src/pages/[application]/backend/database/_layout.svelte
@@ -12,7 +12,7 @@
onMount(async () => {
if ($store.appInstances.length > 0) {
await selectDatabase($store.appInstances[0])
- $goto(`./${$backendUiStore.selectedDatabase.id}`)
+ $goto(`./${$backendUiStore.selectedDatabase._id}`)
}
})
diff --git a/packages/builder/src/pages/[application]/backend/database/index.svelte b/packages/builder/src/pages/[application]/backend/database/index.svelte
index 668a62fbd..09c7c773f 100644
--- a/packages/builder/src/pages/[application]/backend/database/index.svelte
+++ b/packages/builder/src/pages/[application]/backend/database/index.svelte
@@ -12,7 +12,7 @@
onMount(async () => {
if ($store.appInstances.length > 0) {
await selectDatabase($store.appInstances[0])
- $goto(`../${$backendUiStore.selectedDatabase.id}`)
+ $goto(`../${$backendUiStore.selectedDatabase._id}`)
}
})
diff --git a/packages/builder/src/pages/index.svelte b/packages/builder/src/pages/index.svelte
index cce7d053d..7c1fc5920 100644
--- a/packages/builder/src/pages/index.svelte
+++ b/packages/builder/src/pages/index.svelte
@@ -8,7 +8,7 @@
let promise = getApps()
async function getApps() {
- const res = await fetch(`/api/${$store.clientId}/applications`)
+ const res = await fetch(`/api/applications`)
const json = await res.json()
if (res.ok) {
diff --git a/packages/cli/src/commands/init/initHandler.js b/packages/cli/src/commands/init/initHandler.js
index 5bcf0960f..0467633ee 100644
--- a/packages/cli/src/commands/init/initHandler.js
+++ b/packages/cli/src/commands/init/initHandler.js
@@ -3,10 +3,8 @@ const { exists, readFile, writeFile, ensureDir } = require("fs-extra")
const chalk = require("chalk")
const { serverFileName, xPlatHomeDir } = require("../../common")
const { join } = require("path")
-const initialiseClientDb = require("@budibase/server/src/db/initialiseClientDb")
const Sqrl = require("squirrelly")
const uuid = require("uuid")
-const CouchDB = require("@budibase/server/src/db/client")
module.exports = opts => {
run(opts)
@@ -15,6 +13,7 @@ module.exports = opts => {
const run = async opts => {
try {
await ensureAppDir(opts)
+ await setEnvironmentVariables(opts)
await prompts(opts)
await createClientDatabase(opts)
await createDevEnvFile(opts)
@@ -24,18 +23,22 @@ const run = async opts => {
}
}
-const ensureAppDir = async opts => {
- opts.dir = xPlatHomeDir(opts.dir)
- await ensureDir(opts.dir)
-
+const setEnvironmentVariables = async opts => {
if (opts.database === "local") {
const dataDir = join(opts.dir, ".data")
await ensureDir(dataDir)
process.env.COUCH_DB_URL =
dataDir + (dataDir.endsWith("/") || dataDir.endsWith("\\") ? "" : "/")
+ } else {
+ process.env.COUCH_DB_URL = opts.couchDbUrl
}
}
+const ensureAppDir = async opts => {
+ opts.dir = xPlatHomeDir(opts.dir)
+ await ensureDir(opts.dir)
+}
+
const prompts = async opts => {
const questions = [
{
@@ -56,7 +59,14 @@ const prompts = async opts => {
}
const createClientDatabase = async opts => {
+ // cannot be a top level require as it
+ // will cause environment module to be loaded prematurely
+ const clientDb = require("@budibase/server/src/db/clientDb")
+
if (opts.clientId === "new") {
+ // cannot be a top level require as it
+ // will cause environment module to be loaded prematurely
+ const CouchDB = require("@budibase/server/src/db/client")
const existing = await CouchDB.allDbs()
let i = 0
@@ -64,12 +74,11 @@ const createClientDatabase = async opts => {
while (isExisting) {
i += 1
opts.clientId = i.toString()
- isExisting = existing.includes(`client-${opts.clientId}`)
+ isExisting = existing.includes(clientDb.name(opts.clientId))
}
}
- const db = new CouchDB(`client-${opts.clientId}`)
- await initialiseClientDb(db)
+ await clientDb.create(opts.clientId)
}
const createDevEnvFile = async opts => {
diff --git a/packages/cli/src/commands/new/newHandler.js b/packages/cli/src/commands/new/newHandler.js
index dec20bedd..e020c5f9d 100644
--- a/packages/cli/src/commands/new/newHandler.js
+++ b/packages/cli/src/commands/new/newHandler.js
@@ -1,11 +1,6 @@
const { xPlatHomeDir } = require("../../common")
const dotenv = require("dotenv")
-const createInstance = require("@budibase/server/src/api/controllers/instance")
- .create
-const createApplication = require("@budibase/server/src/api/controllers/application")
- .create
-const buildPage = require("@budibase/server/src/utilities/builder/buildPage")
-const { copy, readJSON, writeJSON, remove, exists } = require("fs-extra")
+const { copy, readJSON, writeJSON, exists } = require("fs-extra")
const { resolve, join } = require("path")
const chalk = require("chalk")
const { exec } = require("child_process")
@@ -24,7 +19,9 @@ const run = async opts => {
exec(`cd ${join(opts.dir, opts.applicationId)} && npm install`)
console.log(chalk.green(`Budibase app ${opts.name} created!`))
} catch (error) {
- console.error(chalk.red("Error creating new app", error))
+ console.error(
+ chalk.red("Error creating new app", JSON.stringify(error, { space: 2 }))
+ )
}
}
@@ -37,10 +34,18 @@ const createAppInstance = async opts => {
body: {},
}
- await createApplication(createAppCtx)
- opts.applicationId = createAppCtx.body.id
- console.log(chalk.green(`Application Created: ${createAppCtx.body.id}`))
- await createInstance({
+ // this cannot be a top level require as it will cause
+ // the environment module to be loaded prematurely
+ const appController = require("@budibase/server/src/api/controllers/application")
+ await appController.create(createAppCtx)
+
+ opts.applicationId = createAppCtx.body._id
+ console.log(chalk.green(`Application Created: ${createAppCtx.body._id}`))
+
+ // this cannot be a top level require as it will cause
+ // the environment module to be loaded prematurely
+ const instanceController = require("@budibase/server/src/api/controllers/instance")
+ await instanceController.create({
params: {
clientId: process.env.CLIENT_ID,
applicationId: opts.applicationId,
@@ -49,6 +54,7 @@ const createAppInstance = async opts => {
body: { name: `dev-${process.env.CLIENT_ID}` },
},
})
+
console.log(chalk.green(`Default Instance Created`))
}
@@ -71,4 +77,4 @@ const createEmptyAppPackage = async opts => {
packageJson.name = opts.name
await writeJSON(packageJsonPath, packageJson)
-}
\ No newline at end of file
+}
diff --git a/packages/cli/src/commands/run/runHandler.js b/packages/cli/src/commands/run/runHandler.js
index cdb75b47c..04b21a4ff 100644
--- a/packages/cli/src/commands/run/runHandler.js
+++ b/packages/cli/src/commands/run/runHandler.js
@@ -5,6 +5,12 @@ module.exports = ({ dir }) => {
dir = xPlatHomeDir(dir)
process.env.BUDIBASE_DIR = resolve(dir)
require("dotenv").config({ path: resolve(dir, ".env") })
- require("@budibase/server/src/app")
- console.log(`Budibase Builder running on port ${process.env.PORT}..`)
+ console.log("dotenv loaded")
+
+ // dont make this a variable or top level require
+ // ti will cause environment module to be loaded prematurely
+ require("@budibase/server/src/app")().then(server => {
+ server.on("close", () => console.log("Server Closed"))
+ console.log(`Budibase running on ${JSON.stringify(server.address())}`)
+ })
}
diff --git a/packages/server/.env.template b/packages/server/.env.template
index 16ca2e5a6..bc2e7954a 100644
--- a/packages/server/.env.template
+++ b/packages/server/.env.template
@@ -2,10 +2,6 @@
# http://admin:password@localhost:5984
COUCH_DB_URL={{couchDbUrl}}
-# local (PouchDB) - default for dev
-# remote (CouchDB) - required couch db installation
-DATABASE_TYPE={{database}}
-
# identifies a client database - i.e. group of apps
CLIENT_ID={{clientId}}
@@ -13,8 +9,7 @@ CLIENT_ID={{clientId}}
ADMIN_SECRET={{adminSecret}}
# used to create cookie hashes
-COOKIE_KEY_1={{cookieKey1}}
-COOKIE_KEY_2={{cookieKey2}}
+JWT_SECRET={{cookieKey1}}
# port to run http server on
PORT=4001
\ No newline at end of file
diff --git a/packages/server/.vscode/launch.json b/packages/server/.vscode/launch.json
index 8e1e3fc3e..964e9297f 100644
--- a/packages/server/.vscode/launch.json
+++ b/packages/server/.vscode/launch.json
@@ -8,41 +8,119 @@
"type": "node",
"request": "launch",
"name": "Start Server",
- "program": "${workspaceFolder}/src/index.js"
- },
- {
- "type": "node",
- "request": "launch",
- "name": "Jest App Server",
- "program": "${workspaceFolder}/node_modules/.bin/jest",
- "args": ["apps", "--runInBand"],
- "console": "integratedTerminal",
- "internalConsoleOptions": "neverOpen",
- "disableOptimisticBPs": true,
- "windows": {
- "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
- }
- },
- {
- "type": "node",
- "request": "launch",
- "name": "Jest Builder",
- "program": "${workspaceFolder}/node_modules/.bin/jest",
- "args": ["builder", "--runInBand"],
- "console": "integratedTerminal",
- "internalConsoleOptions": "neverOpen",
- "disableOptimisticBPs": true,
- "windows": {
- "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
- }
- },
- {
- "type": "node",
- "request": "launch",
- "name": "Initialise Budibase",
- "program": "yarn",
- "args": ["run", "initialise"],
- "console": "externalTerminal"
+ "program": "${workspaceFolder}/../cli/bin/budi"
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - All",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": [],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - Users",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["user.spec", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - Instances",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["instance.spec", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
}
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - Records",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["record.spec", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - Models",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["model.spec", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - Views",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["view.spec", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest - Applications",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["application.spec", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Jest Builder",
+ "program": "${workspaceFolder}/node_modules/.bin/jest",
+ "args": ["builder", "--runInBand"],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "disableOptimisticBPs": true,
+ "windows": {
+ "program": "${workspaceFolder}/node_modules/jest-cli/bin/jest",
+ }
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Initialise Budibase",
+ "program": "yarn",
+ "args": ["run", "initialise"],
+ "console": "externalTerminal"
+ }
]
}
\ No newline at end of file
diff --git a/packages/server/package.json b/packages/server/package.json
index 1aa15dac4..42d56712c 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -76,11 +76,13 @@
"eslint": "^6.8.0",
"jest": "^24.8.0",
"nodemon": "^2.0.2",
+ "pouchdb-adapter-memory": "^7.2.1",
"server-destroy": "^1.0.1",
"supertest": "^4.0.2"
},
"jest": {
- "testEnvironment": "node"
+ "testEnvironment": "node",
+ "setupFiles": ["./scripts/jestSetup.js"]
},
"gitHead": "b1f4f90927d9e494e513220ef060af28d2d42455"
}
diff --git a/packages/server/scripts/jestSetup.js b/packages/server/scripts/jestSetup.js
new file mode 100644
index 000000000..8b68f0850
--- /dev/null
+++ b/packages/server/scripts/jestSetup.js
@@ -0,0 +1,11 @@
+const { tmpdir } = require("os")
+
+process.env.NODE_ENV = "jest"
+process.env.JWT_SECRET = "test-jwtsecret"
+process.env.CLIENT_ID = "test-client-id"
+process.env.BUDIBASE_DIR = tmpdir("budibase-unittests")
+process.env.ADMIN_SECRET = "test-admin-secret"
+
+// makes the output of the tests messy
+// but please temporarily enable for debugging :)
+process.env.LOGGER = "off"
diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js
index 7da1cc0f4..8160e4a5b 100644
--- a/packages/server/src/api/controllers/application.js
+++ b/packages/server/src/api/controllers/application.js
@@ -1,9 +1,12 @@
const CouchDB = require("../../db")
+const ClientDb = require("../../db/clientDb")
const { getPackageForBuilder } = require("../../utilities/builder")
+const uuid = require("uuid")
+const env = require("../../environment")
exports.fetch = async function(ctx) {
- const clientDb = new CouchDB(`client-${ctx.params.clientId}`)
- const body = await clientDb.query("client/by_type", {
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
+ const body = await db.query("client/by_type", {
include_docs: true,
key: ["app"],
})
@@ -12,14 +15,16 @@ exports.fetch = async function(ctx) {
}
exports.fetchAppPackage = async function(ctx) {
- const clientDb = new CouchDB(`client-${ctx.params.clientId}`)
- const application = await clientDb.get(ctx.params.applicationId)
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
+ const application = await db.get(ctx.params.applicationId)
ctx.body = await getPackageForBuilder(ctx.config, application)
}
exports.create = async function(ctx) {
- const clientDb = new CouchDB(`client-${ctx.params.clientId}`)
- const { id, rev } = await clientDb.post({
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
+
+ const newApplication = {
+ _id: uuid.v4().replace(/-/g, ""),
type: "app",
instances: [],
userInstanceMap: {},
@@ -28,11 +33,10 @@ exports.create = async function(ctx) {
"@budibase/materialdesign-components",
],
...ctx.request.body,
- })
-
- ctx.body = {
- id,
- rev,
- message: `Application ${ctx.request.body.name} created successfully`,
}
+
+ const { rev } = await db.post(newApplication)
+ newApplication._rev = rev
+ ctx.body = newApplication
+ ctx.message = `Application ${ctx.request.body.name} created successfully`
}
diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js
index 7b85484d9..4cfc2f438 100644
--- a/packages/server/src/api/controllers/auth.js
+++ b/packages/server/src/api/controllers/auth.js
@@ -1,6 +1,8 @@
const jwt = require("jsonwebtoken")
const CouchDB = require("../../db")
+const ClientDb = require("../../db/clientDb")
const bcrypt = require("../../utilities/bcrypt")
+const env = require("../../environment")
exports.authenticate = async ctx => {
const { username, password } = ctx.request.body
@@ -13,7 +15,7 @@ exports.authenticate = async ctx => {
const appId = referer[3]
// find the instance that the user is associated with
- const db = new CouchDB(`client-${process.env.CLIENT_ID}`)
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const app = await db.get(appId)
const instanceId = app.userInstanceMap[username]
diff --git a/packages/server/src/api/controllers/client.js b/packages/server/src/api/controllers/client.js
index 60e294316..433bf58c3 100644
--- a/packages/server/src/api/controllers/client.js
+++ b/packages/server/src/api/controllers/client.js
@@ -1,36 +1,18 @@
-const CouchDB = require("../../db")
+const { create, destroy } = require("../../db/clientDb")
+const env = require("../../environment")
exports.getClientId = async function(ctx) {
- ctx.body = process.env.CLIENT_ID
+ ctx.body = env.CLIENT_ID
}
exports.create = async function(ctx) {
- const clientId = `client-${ctx.request.body.clientId}`
- const db = new CouchDB(clientId)
-
- await db.put({
- _id: "_design/client",
- views: {
- by_type: {
- map: function(doc) {
- emit([doc.type], doc._id)
- }.toString(),
- },
- },
- })
-
- ctx.body = {
- message: `Client Database ${clientId} successfully provisioned.`,
- }
+ await create(env.CLIENT_ID)
+ ctx.status = 200
+ ctx.message = `Client Database ${env.CLIENT_ID} successfully provisioned.`
}
exports.destroy = async function(ctx) {
- const dbId = `client-${ctx.params.clientId}`
-
- await new CouchDB(dbId).destroy()
-
- ctx.body = {
- status: 200,
- message: `Client Database ${dbId} successfully deleted.`,
- }
+ await destroy(env.CLIENT_ID)
+ ctx.status = 200
+ ctx.message = `Client Database ${env.CLIENT_ID} successfully deleted.`
}
diff --git a/packages/server/src/api/controllers/component.js b/packages/server/src/api/controllers/component.js
index 3523ed3f2..0b0782655 100644
--- a/packages/server/src/api/controllers/component.js
+++ b/packages/server/src/api/controllers/component.js
@@ -1,12 +1,14 @@
const CouchDB = require("../../db")
+const ClientDb = require("../../db/clientDb")
const { resolve, join } = require("path")
const {
budibaseTempDir,
budibaseAppsDir,
} = require("../../utilities/budibaseDir")
+const env = require("../../environment")
exports.fetchAppComponentDefinitions = async function(ctx) {
- const db = new CouchDB(`client-${ctx.params.clientId}`)
+ const db = new CouchDB(ClientDb.name(env.CLIENT_ID))
const app = await db.get(ctx.params.appId)
const componentDefinitions = app.componentLibraries.reduce(
diff --git a/packages/server/src/api/controllers/instance.js b/packages/server/src/api/controllers/instance.js
index 7e0e0eef1..19edf5329 100644
--- a/packages/server/src/api/controllers/instance.js
+++ b/packages/server/src/api/controllers/instance.js
@@ -1,10 +1,14 @@
const CouchDB = require("../../db")
+const client = require("../../db/clientDb")
const uuid = require("uuid")
+const env = require("../../environment")
exports.create = async function(ctx) {
const instanceName = ctx.request.body.name
- const instanceId = `app_${ctx.params.applicationId.substring(6)}_inst_${uuid.v4()}`
- const { clientId, applicationId } = ctx.params
+ const uid = uuid.v4().replace(/-/g, "")
+ const instanceId = `inst_${ctx.params.applicationId.substring(0,7)}_${uid}`
+ const { applicationId } = ctx.params
+ const clientId = env.CLIENT_ID
const db = new CouchDB(instanceId)
await db.put({
_id: "_design/database",
@@ -29,18 +33,15 @@ exports.create = async function(ctx) {
})
// Add the new instance under the app clientDB
- const clientDatabaseId = `client-${clientId}`
- const clientDb = new CouchDB(clientDatabaseId)
+ const clientDb = new CouchDB(client.name(clientId))
const budibaseApp = await clientDb.get(applicationId)
- const instance = { id: instanceId, name: instanceName }
+ const instance = { _id: instanceId, name: instanceName }
budibaseApp.instances.push(instance)
await clientDb.put(budibaseApp)
- ctx.body = {
- message: `Instance Database ${instanceName} successfully provisioned.`,
- status: 200,
- instance,
- }
+ ctx.status = 200
+ ctx.message = `Instance Database ${instanceName} successfully provisioned.`
+ ctx.body = instance
}
exports.destroy = async function(ctx) {
@@ -50,15 +51,13 @@ exports.destroy = async function(ctx) {
// remove instance from client application document
const { metadata } = designDoc
- const clientDb = new CouchDB(metadata.clientId)
+ const clientDb = new CouchDB(client.name(metadata.clientId))
const budibaseApp = await clientDb.get(metadata.applicationId)
budibaseApp.instances = budibaseApp.instances.filter(
instance => instance !== ctx.params.instanceId
)
await clientDb.put(budibaseApp)
- ctx.body = {
- message: `Instance Database ${ctx.params.instanceId} successfully destroyed.`,
- status: 200,
- }
+ ctx.status = 200
+ ctx.message = `Instance Database ${ctx.params.instanceId} successfully destroyed.`
}
diff --git a/packages/server/src/api/controllers/model.js b/packages/server/src/api/controllers/model.js
index 9c90ebbba..5eba25d05 100644
--- a/packages/server/src/api/controllers/model.js
+++ b/packages/server/src/api/controllers/model.js
@@ -1,4 +1,5 @@
const CouchDB = require("../../db")
+const uuid = require("uuid")
exports.fetch = async function(ctx) {
const db = new CouchDB(ctx.params.instanceId)
@@ -11,17 +12,21 @@ exports.fetch = async function(ctx) {
exports.create = async function(ctx) {
const db = new CouchDB(ctx.params.instanceId)
- const newModel = await db.post({
+ const newModel = {
type: "model",
...ctx.request.body,
- })
+ _id: uuid.v4().replace(/-/g, ""),
+ }
+
+ const result = await db.post(newModel)
+ newModel._rev = result.rev
const designDoc = await db.get("_design/database")
designDoc.views = {
...designDoc.views,
- [`all_${newModel.id}`]: {
+ [`all_${newModel._id}`]: {
map: `function(doc) {
- if (doc.modelId === "${newModel.id}") {
+ if (doc.modelId === "${newModel._id}") {
emit(doc[doc.key], doc._id);
}
}`,
@@ -29,15 +34,9 @@ exports.create = async function(ctx) {
}
await db.put(designDoc)
- ctx.body = {
- message: `Model ${ctx.request.body.name} created successfully.`,
- status: 200,
- model: {
- _id: newModel.id,
- _rev: newModel.rev,
- ...ctx.request.body,
- },
- }
+ ctx.status = 200
+ ctx.message = `Model ${ctx.request.body.name} created successfully.`
+ ctx.body = newModel
}
exports.update = async function(ctx) {}
@@ -45,8 +44,8 @@ exports.update = async function(ctx) {}
exports.destroy = async function(ctx) {
const db = new CouchDB(ctx.params.instanceId)
- const model = await db.remove(ctx.params.modelId, ctx.params.revId)
- const modelViewId = `all_${model.id}`
+ await db.remove(ctx.params.modelId, ctx.params.revId)
+ const modelViewId = `all_${ctx.params.modelId}`
// Delete all records for that model
const records = await db.query(`database/${modelViewId}`)
@@ -59,8 +58,6 @@ exports.destroy = async function(ctx) {
delete designDoc.views[modelViewId]
await db.put(designDoc)
- ctx.body = {
- message: `Model ${model.id} deleted.`,
- status: 200,
- }
+ ctx.status = 200
+ ctx.message = `Model ${ctx.params.modelId} deleted.`
}
diff --git a/packages/server/src/api/controllers/record.js b/packages/server/src/api/controllers/record.js
index 313d852a9..b6b7fc62b 100644
--- a/packages/server/src/api/controllers/record.js
+++ b/packages/server/src/api/controllers/record.js
@@ -1,5 +1,6 @@
const CouchDB = require("../../db")
const Ajv = require("ajv")
+const uuid = require("uuid")
const ajv = new Ajv()
@@ -7,6 +8,10 @@ exports.save = async function(ctx) {
const db = new CouchDB(ctx.params.instanceId)
const record = ctx.request.body
+ if (!record._rev && !record._id) {
+ record._id = uuid.v4().replace(/-/, "")
+ }
+
// validation with ajv
const model = await db.get(record.modelId)
const validate = ajv.compile({
@@ -23,18 +28,15 @@ exports.save = async function(ctx) {
return
}
- const existingRecord = record._id && (await db.get(record._id))
+ const existingRecord = record._rev && (await db.get(record._id))
if (existingRecord) {
- const response = await db.put({ ...record, _id: existingRecord._id })
- ctx.body = {
- message: `${model.name} updated successfully.`,
- status: 200,
- record: {
- ...record,
- ...response,
- },
- }
+ const response = await db.put(record)
+ record._rev = response.rev
+ record.type = "record"
+ ctx.body = record
+ ctx.status = 200
+ ctx.message = `${model.name} updated successfully.`
return
}
@@ -45,10 +47,7 @@ exports.save = async function(ctx) {
// record: record,
// })
- ctx.body = {
- ...record,
- ...response
- }
+ ctx.body = record
ctx.status = 200
ctx.message = `${model.name} created successfully`
}
diff --git a/packages/server/src/api/controllers/static.js b/packages/server/src/api/controllers/static.js
index ba3a0cb21..32542de54 100644
--- a/packages/server/src/api/controllers/static.js
+++ b/packages/server/src/api/controllers/static.js
@@ -4,10 +4,11 @@ const {
budibaseAppsDir,
budibaseTempDir,
} = require("../../utilities/budibaseDir")
+const env = require("../../environment")
exports.serveBuilder = async function(ctx) {
let builderPath = resolve(__dirname, "../../../builder")
-
+ ctx.cookies.set("builder:token", env.ADMIN_SECRET)
await send(ctx, ctx.file, { root: ctx.devPath || builderPath })
}
diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js
index 0868e0f97..2be0132a4 100644
--- a/packages/server/src/api/controllers/user.js
+++ b/packages/server/src/api/controllers/user.js
@@ -1,5 +1,9 @@
const CouchDB = require("../../db")
+const clientDb = require("../../db/clientDb")
const bcrypt = require("../../utilities/bcrypt")
+const env = require("../../environment")
+
+const getUserId = userName => `user_${userName}`
exports.fetch = async function(ctx) {
const database = new CouchDB(ctx.params.instanceId)
@@ -13,45 +17,51 @@ exports.fetch = async function(ctx) {
exports.create = async function(ctx) {
const database = new CouchDB(ctx.params.instanceId)
+ const appId = (await database.get("_design/database")).metadata.applicationId
const { username, password, name } = ctx.request.body
if (!username || !password) ctx.throw(400, "Username and Password Required.")
const response = await database.post({
+ _id: getUserId(username),
username,
password: await bcrypt.hash(password),
- name,
+ name: name || username,
type: "user",
})
// the clientDB needs to store a map of users against the app
- const clientDb = new CouchDB(`client-${process.env.CLIENT_ID}`)
- const app = await clientDb.get(ctx.params.appId)
+ const db = new CouchDB(clientDb.name(env.CLIENT_ID))
+ const app = await db.get(appId)
app.userInstanceMap = {
...app.userInstanceMap,
[username]: ctx.params.instanceId,
}
- await clientDb.put(app)
+ await db.put(app)
+ ctx.status = 200
+ ctx.message = "User created successfully."
ctx.body = {
- user: {
- id: response.id,
- rev: response.rev,
- username,
- name,
- },
- message: `User created successfully.`,
- status: 200,
+ _rev: response.rev,
+ username,
+ name,
}
}
exports.destroy = async function(ctx) {
const database = new CouchDB(ctx.params.instanceId)
- const response = await database.destroy(ctx.params.userId)
+ await database.destroy(getUserId(ctx.params.username))
+ ctx.message = `User ${ctx.params.username} deleted.`
+ ctx.status = 200
+}
+
+exports.find = async function(ctx) {
+ const database = new CouchDB(ctx.params.instanceId)
+ const user = await database.get(getUserId(ctx.params.username))
ctx.body = {
- ...response,
- message: `User deleted.`,
- status: 200,
+ username: user.username,
+ name: user.name,
+ _rev: user._rev,
}
}
diff --git a/packages/server/src/api/controllers/view.js b/packages/server/src/api/controllers/view.js
index 03dc843be..64d3c3b98 100644
--- a/packages/server/src/api/controllers/view.js
+++ b/packages/server/src/api/controllers/view.js
@@ -24,23 +24,17 @@ const controller = {
},
create: async ctx => {
const db = new CouchDB(ctx.params.instanceId)
- const { name, ...viewDefinition } = ctx.request.body
+ const newView = ctx.request.body
const designDoc = await db.get("_design/database")
designDoc.views = {
...designDoc.views,
- [name]: viewDefinition,
+ [newView.name]: newView,
}
- const newView = await db.put(designDoc)
+ await db.put(designDoc)
- ctx.body = {
- view: {
- ...ctx.request.body,
- ...newView,
- },
- message: `View ${name} created successfully.`,
- status: 200,
- }
+ ctx.body = newView
+ ctx.message = `View ${newView.name} created successfully.`
},
destroy: async ctx => {
const db = new CouchDB(ctx.params.instanceId)
diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js
index 65fb60ee7..2e3cd87b4 100644
--- a/packages/server/src/api/index.js
+++ b/packages/server/src/api/index.js
@@ -18,6 +18,7 @@ const {
} = require("./routes")
const router = new Router()
+const env = require("../environment")
router
.use(
@@ -34,9 +35,9 @@ router
.use(async (ctx, next) => {
ctx.config = {
latestPackagesFolder: budibaseAppsDir(),
- jwtSecret: process.env.JWT_SECRET,
+ jwtSecret: env.JWT_SECRET,
}
- ctx.isDev = process.env.NODE_ENV !== "production"
+ ctx.isDev = env.NODE_ENV !== "production" && env.NODE_ENV !== "jest"
await next()
})
.use(authenticated)
@@ -46,7 +47,7 @@ router.use(async (ctx, next) => {
try {
await next()
} catch (err) {
- console.trace(err)
+ if (env.LOGGER !== "off") console.trace(err)
ctx.status = err.status || err.statusCode || 500
ctx.body = {
message: err.message,
diff --git a/packages/server/src/api/routes/application.js b/packages/server/src/api/routes/application.js
index c2db67c49..dddf64a71 100644
--- a/packages/server/src/api/routes/application.js
+++ b/packages/server/src/api/routes/application.js
@@ -4,8 +4,8 @@ const controller = require("../controllers/application")
const router = Router()
router
- .get("/api/:clientId/applications", controller.fetch)
- .get("/api/:clientId/:applicationId/appPackage", controller.fetchAppPackage)
- .post("/api/:clientId/applications", controller.create)
+ .get("/api/applications", controller.fetch)
+ .get("/api/:applicationId/appPackage", controller.fetchAppPackage)
+ .post("/api/applications", controller.create)
module.exports = router
diff --git a/packages/server/src/api/routes/client.js b/packages/server/src/api/routes/client.js
index 1f9a9dc99..c12b9e14e 100644
--- a/packages/server/src/api/routes/client.js
+++ b/packages/server/src/api/routes/client.js
@@ -1,11 +1,15 @@
const Router = require("@koa/router")
const controller = require("../controllers/client")
+const env = require("../../environment")
const router = Router()
-router
- .get("/api/client/id", controller.getClientId)
- .post("/api/clients", controller.create)
- .delete("/api/clients/:clientId", controller.destroy)
+router.get("/api/client/id", controller.getClientId)
+
+if (env.NODE_ENV === "jest") {
+ router
+ .post("/api/client", controller.create)
+ .delete("/api/client", controller.destroy)
+}
module.exports = router
diff --git a/packages/server/src/api/routes/component.js b/packages/server/src/api/routes/component.js
index 3a5c7224c..5df34381f 100644
--- a/packages/server/src/api/routes/component.js
+++ b/packages/server/src/api/routes/component.js
@@ -4,7 +4,7 @@ const controller = require("../controllers/component")
const router = Router()
router.get(
- "/:clientId/:appId/components/definitions",
+ "/:appId/components/definitions",
controller.fetchAppComponentDefinitions
)
diff --git a/packages/server/src/api/routes/instance.js b/packages/server/src/api/routes/instance.js
index 82aa30250..fd74a98bf 100644
--- a/packages/server/src/api/routes/instance.js
+++ b/packages/server/src/api/routes/instance.js
@@ -4,7 +4,7 @@ const controller = require("../controllers/instance")
const router = Router()
router
- .post("/api/:clientId/:applicationId/instances", controller.create)
+ .post("/api/:applicationId/instances", controller.create)
.delete("/api/instances/:instanceId", controller.destroy)
module.exports = router
diff --git a/packages/server/src/api/routes/static.js b/packages/server/src/api/routes/static.js
index 606173b8f..5909d31d0 100644
--- a/packages/server/src/api/routes/static.js
+++ b/packages/server/src/api/routes/static.js
@@ -1,21 +1,26 @@
const Router = require("@koa/router")
const controller = require("../controllers/static")
const { budibaseTempDir } = require("../../utilities/budibaseDir")
+const env = require("../../environment")
const router = Router()
-router
- .param("file", async (file, ctx, next) => {
- ctx.file = file && file.includes(".") ? file : "index.html"
+router.param("file", async (file, ctx, next) => {
+ ctx.file = file && file.includes(".") ? file : "index.html"
+
+ // Serving the client library from your local dir in dev
+ if (ctx.isDev && ctx.file.startsWith("budibase-client")) {
+ ctx.devPath = budibaseTempDir()
+ }
- // Serving the client library from your local dir in dev
- if (ctx.isDev && ctx.file.startsWith("budibase-client")) {
- ctx.devPath = budibaseTempDir()
- }
+ await next()
+})
- await next()
- })
- .get("/_builder/:file*", controller.serveBuilder)
+if (env.NODE_ENV !== "production") {
+ router.get("/_builder/:file*", controller.serveBuilder)
+}
+
+router
.get("/:appId/componentlibrary", controller.serveComponentLibrary)
.get("/:appId/:file*", controller.serveApp)
diff --git a/packages/server/src/api/routes/tests/application.spec.js b/packages/server/src/api/routes/tests/application.spec.js
index 70a4206c2..3619b5947 100644
--- a/packages/server/src/api/routes/tests/application.spec.js
+++ b/packages/server/src/api/routes/tests/application.spec.js
@@ -1,37 +1,58 @@
-const supertest = require("supertest");
-const app = require("../../../app");
-const { createClientDatabase, destroyDatabase } = require("./couchTestUtils");
-
-
-const CLIENT_DB_ID = "client-testing";
+const {
+ createClientDatabase,
+ createApplication,
+ destroyClientDatabase,
+ supertest,
+ defaultHeaders
+} = require("./couchTestUtils")
describe("/applications", () => {
- let request;
- let server;
+ let request
+ let server
beforeAll(async () => {
- server = app;
- request = supertest(server);
- await createClientDatabase();
+ ({ request, server } = await supertest())
});
+ beforeEach(async () => {
+ await createClientDatabase(request)
+ })
+
+ afterEach(async () => {
+ await destroyClientDatabase(request)
+ })
+
afterAll(async () => {
- server.close();
- await destroyDatabase(CLIENT_DB_ID)
+ server.close()
})
describe("create", () => {
- it("returns a success message when the application is successfully created", done => {
- request
- .post("/api/testing/applications")
+ it("returns a success message when the application is successfully created", async () => {
+ const res = await request
+ .post("/api/applications")
.send({ name: "My App" })
- .set("Accept", "application/json")
+ .set(defaultHeaders)
+ .expect('Content-Type', /json/)
+ .expect(200)
+ expect(res.res.statusMessage).toEqual("Application My App created successfully")
+ expect(res.body._id).toBeDefined()
+ })
+ })
+
+ describe("fetch", () => {
+ it("lists all applications", async () => {
+
+ await createApplication(request, "app1")
+ await createApplication(request, "app2")
+
+ const res = await request
+ .get("/api/applications")
+ .set(defaultHeaders)
.expect('Content-Type', /json/)
.expect(200)
- .end((err, res) => {
- expect(res.body.message).toEqual("Application My App created successfully");
- done();
- });
- })
- });
-});
+
+ expect(res.body.length).toBe(2)
+ })
+ })
+
+})
diff --git a/packages/server/src/api/routes/tests/client.spec.js b/packages/server/src/api/routes/tests/client.spec.js
index a4533a123..165290569 100644
--- a/packages/server/src/api/routes/tests/client.spec.js
+++ b/packages/server/src/api/routes/tests/client.spec.js
@@ -1,58 +1,48 @@
-const supertest = require("supertest");
-const app = require("../../../app");
-const { createClientDatabase, destroyClientDatabase } = require("./couchTestUtils")
+const {
+ createClientDatabase,
+ destroyClientDatabase,
+ supertest,
+} = require("./couchTestUtils")
-
-const CLIENT_DB_ID = "client-testing";
+const CLIENT_ID = "test-client-id"
describe("/clients", () => {
let request;
let server;
- let db;
- beforeAll(async () => {
- server = app
- request = supertest(server);
+ beforeEach(async () => {
+ ({ request, server } = await supertest())
});
- afterAll(async () => {
+ afterEach(async () => {
server.close();
})
describe("create", () => {
- afterEach(async () => {
- await destroyClientDatabase();
- });
- it("returns a success message when the client database is successfully created", done => {
- request
- .post("/api/clients")
+ it("returns a success message when the client database is successfully created", async () => {
+ const res = await request
+ .post("/api/client")
.send({ clientId: "testing" })
.set("Accept", "application/json")
- .expect('Content-Type', /json/)
.expect(200)
- .end((err, res) => {
- expect(res.body.message).toEqual(`Client Database ${CLIENT_DB_ID} successfully provisioned.`);
- done();
- });
- })
- });
+
+ expect(res.res.statusMessage).toEqual(`Client Database ${process.env.CLIENT_ID} successfully provisioned.`);
+ })
+ });
describe("destroy", () => {
beforeEach(async () => {
- db = await createClientDatabase();
+ db = await createClientDatabase(request);
});
- it("returns a success message when the client database is successfully destroyed", async done => {
- request
- .delete(`/api/clients/testing`)
+ it("returns a success message when the client database is successfully destroyed", async () => {
+ const res = await request
+ .delete(`/api/client`)
.set("Accept", "application/json")
- .expect('Content-Type', /json/)
.expect(200)
- .end((err, res) => {
- expect(res.body.message).toEqual(`Client Database ${CLIENT_DB_ID} successfully deleted.`);
- done();
- });
- })
- });
+ expect(res.res.statusMessage).toEqual(`Client Database ${process.env.CLIENT_ID} successfully deleted.`);
+
+ })
+ });
});
diff --git a/packages/server/src/api/routes/tests/couchTestUtils.js b/packages/server/src/api/routes/tests/couchTestUtils.js
index e6837e599..eacb32b63 100644
--- a/packages/server/src/api/routes/tests/couchTestUtils.js
+++ b/packages/server/src/api/routes/tests/couchTestUtils.js
@@ -1,8 +1,34 @@
const CouchDB = require("../../../db")
-const CLIENT_DB_ID = "client-testing"
-const TEST_APP_ID = "test-app"
+const supertest = require("supertest")
+const app = require("../../../app")
-exports.createModel = async (instanceId, model) => {
+exports.supertest = async () => {
+ let request
+ let port = 4002
+ let started = false
+ let server
+ while (!started && port < 4020) {
+ try {
+ server = await app(port)
+ started = true
+ } catch (e) {
+ if (e.code === "EADDRINUSE") port = port + 1
+ else throw e
+ }
+ }
+
+ if (!started) throw Error("Application failed to start")
+
+ request = supertest(server)
+ return { request, server }
+}
+
+exports.defaultHeaders = {
+ Accept: "application/json",
+ Authorization: "Basic test-admin-secret",
+}
+
+exports.createModel = async (request, instanceId, model) => {
model = model || {
name: "TestModel",
type: "model",
@@ -11,72 +37,60 @@ exports.createModel = async (instanceId, model) => {
name: { type: "string" },
},
}
- const db = new CouchDB(instanceId)
- const response = await db.post(model)
-
- const designDoc = await db.get("_design/database")
- designDoc.views = {
- ...designDoc.views,
- [`all_${response.id}`]: {
- map: `function(doc) {
- if (doc.modelId === "${response.id}") {
- emit(doc[doc.key], doc._id);
- }
- }`,
- },
- }
- await db.put(designDoc)
- return {
- ...response,
- ...model,
- }
+ const res = await request
+ .post(`/api/${instanceId}/models`)
+ .set(exports.defaultHeaders)
+ .send(model)
+ return res.body
}
-exports.createClientDatabase = async () => {
- const db = new CouchDB(CLIENT_DB_ID)
-
- await db.put({
- _id: "_design/client",
- views: {
- by_type: {
- map: function(doc) {
- emit([doc.type], doc._id)
- },
- }.toString(),
- },
- })
-
- await db.put({
- _id: TEST_APP_ID,
- type: "app",
- instances: [],
- })
-
- return db
+exports.createClientDatabase = async request => {
+ const res = await request
+ .post("/api/client")
+ .set(exports.defaultHeaders)
+ .send({})
+ return res.body
}
-exports.destroyClientDatabase = async () => new CouchDB(CLIENT_DB_ID).destroy()
+exports.createApplication = async (request, name = "test_application") => {
+ const res = await request
+ .post("/api/applications")
+ .set(exports.defaultHeaders)
+ .send({
+ name,
+ })
+ return res.body
+}
-exports.createInstanceDatabase = async instanceId => {
- const db = new CouchDB(instanceId)
+exports.destroyClientDatabase = async request => {
+ await request
+ .delete(`/api/client`)
+ .set(exports.defaultHeaders)
+ .send({})
+}
- await db.put({
- _id: "_design/database",
- metadata: {
- clientId: CLIENT_DB_ID,
- applicationId: TEST_APP_ID,
- },
- views: {
- by_type: {
- map: function(doc) {
- emit([doc.type], doc._id)
- }.toString(),
- },
- },
- })
+exports.createInstance = async (request, appId) => {
+ const res = await request
+ .post(`/api/${appId}/instances`)
+ .set(exports.defaultHeaders)
+ .send({
+ name: "test-instance",
+ })
+ return res.body
+}
- return db
+exports.createUser = async (
+ request,
+ instanceId,
+ username = "bill",
+ password = "bills_password"
+) => {
+ const res = await request
+ .post(`/api/${instanceId}/users`)
+ .set(exports.defaultHeaders)
+ .send({ name: "Bill", username, password })
+ return res.body
}
exports.insertDocument = async (databaseId, document) => {
diff --git a/packages/server/src/api/routes/tests/instance.spec.js b/packages/server/src/api/routes/tests/instance.spec.js
index 5f2399f10..0b8bd44cb 100644
--- a/packages/server/src/api/routes/tests/instance.spec.js
+++ b/packages/server/src/api/routes/tests/instance.spec.js
@@ -1,22 +1,19 @@
-const supertest = require("supertest");
-const app = require("../../../app");
const {
- createInstanceDatabase,
+ createInstance,
createClientDatabase,
- destroyClientDatabase
+ createApplication,
+ supertest,
+ defaultHeaders
} = require("./couchTestUtils");
-
-const TEST_INSTANCE_ID = "testing-123";
-const TEST_APP_ID = "test-app";
-
describe("/instances", () => {
- let request;
- let server;
-
+ let TEST_APP_ID;
+ let server
+ let request
beforeAll(async () => {
- server = app
- request = supertest(server);
+ ({ request, server } = await supertest())
+ await createClientDatabase(request);
+ TEST_APP_ID = (await createApplication(request))._id
});
afterAll(async () => {
@@ -25,48 +22,30 @@ describe("/instances", () => {
describe("create", () => {
- beforeEach(async () => {
- clientDb = await createClientDatabase();
- });
-
- afterEach(async () => {
- await destroyClientDatabase();
- });
-
- it("returns a success message when the instance database is successfully created", done => {
- request
- .post(`/api/testing/${TEST_APP_ID}/instances`)
- .send({ name: TEST_INSTANCE_ID })
- .set("Accept", "application/json")
+ it("returns a success message when the instance database is successfully created", async () => {
+ const res = await request
+ .post(`/api/${TEST_APP_ID}/instances`)
+ .send({ name: "test-instance" })
+ .set(defaultHeaders)
.expect('Content-Type', /json/)
.expect(200)
- .end(async (err, res) => {
- expect(res.body.message).toEqual("Instance Database testing-123 successfully provisioned.");
- done();
- });
- })
- });
- describe("destroy", () => {
- beforeEach(async () => {
- await createClientDatabase();
- instanceDb = await createInstanceDatabase(TEST_INSTANCE_ID);
- });
+ expect(res.res.statusMessage).toEqual("Instance Database test-instance successfully provisioned.");
+ expect(res.body._id).toBeDefined();
+
+ })
+ });
- afterEach(async () => {
- await destroyClientDatabase();
- });
+ describe("destroy", () => {
- it("returns a success message when the instance database is successfully deleted", done => {
- request
- .delete(`/api/instances/${TEST_INSTANCE_ID}`)
- .set("Accept", "application/json")
- .expect('Content-Type', /json/)
+ it("returns a success message when the instance database is successfully deleted", async () => {
+ const instance = await createInstance(request, TEST_APP_ID);
+ const res = await request
+ .delete(`/api/instances/${instance._id}`)
+ .set(defaultHeaders)
.expect(200)
- .end(async (err, res) => {
- expect(res.body.message).toEqual("Instance Database testing-123 successfully destroyed.");
- done();
- });
- })
- });
+
+ expect(res.res.statusMessage).toEqual(`Instance Database ${instance._id} successfully destroyed.`);
+ })
+ });
});
diff --git a/packages/server/src/api/routes/tests/model.spec.js b/packages/server/src/api/routes/tests/model.spec.js
index 2f18e7017..e32c94224 100644
--- a/packages/server/src/api/routes/tests/model.spec.js
+++ b/packages/server/src/api/routes/tests/model.spec.js
@@ -1,17 +1,21 @@
-const supertest = require("supertest");
-const app = require("../../../app");
-const { createInstanceDatabase, createModel } = require("./couchTestUtils");
-
-
-const TEST_INSTANCE_ID = "testing-123";
+const {
+ createInstance,
+ createModel,
+ supertest,
+ createClientDatabase,
+ createApplication
+} = require("./couchTestUtils")
describe("/models", () => {
- let request;
- let server;
+ let request
+ let server
+ let app
+ let instance
beforeAll(async () => {
- server = app;
- request = supertest(server);
+ ({ request, server } = await supertest())
+ await createClientDatabase(request)
+ app = await createApplication(request)
});
afterAll(async () => {
@@ -19,19 +23,14 @@ describe("/models", () => {
})
describe("create", () => {
- let db;
beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- });
-
- afterEach(async () => {
- await db.destroy();
+ instance = await createInstance(request, app._id);
});
it("returns a success message when the model is successfully created", done => {
request
- .post(`/api/${TEST_INSTANCE_ID}/models`)
+ .post(`/api/${instance._id}/models`)
.send({
name: "TestModel",
key: "name",
@@ -43,29 +42,24 @@ describe("/models", () => {
.expect('Content-Type', /json/)
.expect(200)
.end(async (err, res) => {
- expect(res.body.message).toEqual("Model TestModel created successfully.");
- expect(res.body.model.name).toEqual("TestModel");
+ expect(res.res.statusMessage).toEqual("Model TestModel created successfully.");
+ expect(res.body.name).toEqual("TestModel");
done();
});
})
});
describe("fetch", () => {
- let testModel;
- let db;
+ let testModel
beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- testModel = await createModel(TEST_INSTANCE_ID);
- });
-
- afterEach(async () => {
- await db.destroy();
+ instance = await createInstance(request, app._id)
+ testModel = await createModel(request, instance._id, testModel)
});
it("returns all the models for that instance in the response body", done => {
request
- .get(`/api/${TEST_INSTANCE_ID}/models`)
+ .get(`/api/${instance._id}/models`)
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
@@ -80,25 +74,20 @@ describe("/models", () => {
describe("destroy", () => {
let testModel;
- let db;
beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- testModel = await createModel(TEST_INSTANCE_ID);
- });
-
- afterEach(async () => {
- await db.destroy();
+ instance = await createInstance(request, app._id)
+ testModel = await createModel(request, instance._id, testModel)
});
it("returns a success response when a model is deleted.", done => {
request
- .delete(`/api/${TEST_INSTANCE_ID}/models/${testModel.id}/${testModel.rev}`)
+ .delete(`/api/${instance._id}/models/${testModel._id}/${testModel._rev}`)
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
.end(async (_, res) => {
- expect(res.body.message).toEqual(`Model ${testModel.id} deleted.`);
+ expect(res.res.statusMessage).toEqual(`Model ${testModel._id} deleted.`);
done();
});
})
diff --git a/packages/server/src/api/routes/tests/record.spec.js b/packages/server/src/api/routes/tests/record.spec.js
index eda78efb3..b75b24513 100644
--- a/packages/server/src/api/routes/tests/record.spec.js
+++ b/packages/server/src/api/routes/tests/record.spec.js
@@ -1,27 +1,23 @@
-const supertest = require("supertest");
-const app = require("../../../app");
-const { createInstanceDatabase, createModel } = require("./couchTestUtils");
-
-const TEST_INSTANCE_ID = "testing-123";
-
-const CONTACT_MODEL = {
- "name": "Contact",
- "type": "model",
- "key": "name",
- "schema": {
- "name": { "type": "string" },
- "age": { "type": "number" }
- }
-};
+const {
+ createApplication,
+ createClientDatabase,
+ createInstance,
+ createModel,
+ supertest
+} = require("./couchTestUtils");
describe("/records", () => {
- let request;
- let server;
- let db;
+ let request
+ let server
+ let instance
+ let model
+ let record
+ let app
beforeAll(async () => {
- server = app;
- request = supertest(server);
+ ({ request, server } = await supertest())
+ await createClientDatabase(request)
+ app = await createApplication(request)
});
afterAll(async () => {
@@ -29,95 +25,94 @@ describe("/records", () => {
})
describe("save, load, update, delete", () => {
- let record;
- let model;
beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- model = await createModel(TEST_INSTANCE_ID, CONTACT_MODEL)
+ instance = await createInstance(request, app._id)
+ model = await createModel(request, instance._id)
record = {
name: "Test Contact",
status: "new",
- modelId: model.id
+ modelId: model._id
}
- });
-
- afterEach(async () => {
- await db.destroy();
- });
+ })
- it("returns a success message when the record is created", done => {
- request
- .post(`/api/${TEST_INSTANCE_ID}/records`)
- .send(record)
+ const createRecord = async r =>
+ await request
+ .post(`/api/${instance._id}/records`)
+ .send(r || record)
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
- .end(async (err, res) => {
- expect(res.res.statusMessage).toEqual("Contact created successfully")
- expect(res.body.name).toEqual("Test Contact")
- expect(res.body._rev).toBeDefined()
- done();
- });
+
+ it("returns a success message when the record is created", async () => {
+ const res = await createRecord()
+ expect(res.res.statusMessage).toEqual(`${model.name} created successfully`)
+ expect(res.body.name).toEqual("Test Contact")
+ expect(res.body._rev).toBeDefined()
})
it("updates a record successfully", async () => {
- const existing = await db.post(record);
+ const rec = await createRecord()
+ const existing = rec.body
const res = await request
- .post(`/api/${TEST_INSTANCE_ID}/records`)
+ .post(`/api/${instance._id}/records`)
.send({
- _id: existing.id,
- _rev: existing.rev,
- modelId: model.id,
+ _id: existing._id,
+ _rev: existing._rev,
+ modelId: model._id,
name: "Updated Name",
})
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
- expect(res.body.message).toEqual("Contact updated successfully.")
- expect(res.body.record.name).toEqual("Updated Name")
+ expect(res.res.statusMessage).toEqual(`${model.name} updated successfully.`)
+ expect(res.body.name).toEqual("Updated Name")
})
it("should load a record", async () => {
- const existing = await db.post(record);
+ const rec = await createRecord()
+ const existing = rec.body
const res = await request
- .get(`/api/${TEST_INSTANCE_ID}/records/${existing.id}`)
+ .get(`/api/${instance._id}/records/${existing._id}`)
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
expect(res.body).toEqual({
...record,
- _id: existing.id,
- _rev: existing.rev
+ _id: existing._id,
+ _rev: existing._rev,
+ type: "record",
})
})
it("should list all records for given modelId", async () => {
const newRecord = {
- modelId: model.id,
+ modelId: model._id,
name: "Second Contact",
status: "new"
}
-
- await db.post(newRecord);
+ await createRecord()
+ await createRecord(newRecord)
const res = await request
- .get(`/api/${TEST_INSTANCE_ID}/all_${newRecord.modelId}/records`)
+ .get(`/api/${instance._id}/all_${newRecord.modelId}/records`)
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(200)
- expect(res.body.length).toBe(1)
- expect(res.body[0].name).toEqual(newRecord.name);
+ expect(res.body.length).toBe(2)
+ expect(res.body.find(r => r.name === newRecord.name)).toBeDefined()
+ expect(res.body.find(r => r.name === record.name)).toBeDefined()
})
it("load should return 404 when record does not exist", async () => {
+ await createRecord()
await request
- .get(`/api/${TEST_INSTANCE_ID}/records/not-a-valid-id`)
+ .get(`/api/${instance._id}/records/not-a-valid-id`)
.set("Accept", "application/json")
.expect('Content-Type', /json/)
.expect(404)
diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js
index 2590297e8..bba748daf 100644
--- a/packages/server/src/api/routes/tests/user.spec.js
+++ b/packages/server/src/api/routes/tests/user.spec.js
@@ -1,75 +1,62 @@
-const supertest = require("supertest");
-const app = require("../../../app");
const {
- createInstanceDatabase
-} = require("./couchTestUtils");
-
-
-const TEST_INSTANCE_ID = "testing-123";
-const TEST_USER = {
- name: "Dave"
-}
+ createClientDatabase,
+ createApplication,
+ createInstance,
+ supertest,
+ defaultHeaders,
+ createUser,
+} = require("./couchTestUtils")
describe("/users", () => {
- let request;
- let server;
+ let request
+ let server
+ let app
+ let instance
beforeAll(async () => {
- server = app
- request = supertest(server);
+ ({ request, server } = await supertest(server))
+ await createClientDatabase(request)
+ app = await createApplication(request)
+ });
+
+ beforeEach(async () => {
+ instance = await createInstance(request, app._id)
});
afterAll(async () => {
server.close();
})
- describe("fetch", () => {
- let db;
+ describe("fetch", () => {
- beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- });
-
- afterEach(async () => {
- await db.destroy();
- });
-
- it("returns a list of users from an instance db", done => {
- request
- .get(`/api/${TEST_INSTANCE_ID}/users`)
- .set("Accept", "application/json")
+ it("returns a list of users from an instance db", async () => {
+ await createUser(request, instance._id, "brenda", "brendas_password")
+ await createUser(request, instance._id, "pam", "pam_password")
+ const res = await request
+ .get(`/api/${instance._id}/users`)
+ .set(defaultHeaders)
.expect('Content-Type', /json/)
.expect(200)
- .end(async (err, res) => {
- const user = res.body[0];
- expect(user.name).toEqual(TEST_USER.name);
- done();
- });
- })
- });
-
- describe("create", () => {
- let db;
+
+ expect(res.body.length).toBe(2)
+ expect(res.body.find(u => u.username === "brenda")).toBeDefined()
+ expect(res.body.find(u => u.username === "pam")).toBeDefined()
+ })
- beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- });
+ })
- afterEach(async () => {
- await db.destroy();
- });
+ describe("create", () => {
- it("returns a success message when a user is successfully created", done => {
- request
- .post(`/api/${TEST_INSTANCE_ID}/users`)
- .send({ name: "Bill", username: "bill1", password: "password" })
- .set("Accept", "application/json")
- .expect('Content-Type', /json/)
+ it("returns a success message when a user is successfully created", async () => {
+ const res = await request
+ .post(`/api/${instance._id}/users`)
+ .set(defaultHeaders)
+ .send({ name: "Bill", username: "bill", password: "bills_password" })
.expect(200)
- .end(async (err, res) => {
- expect(res.body.message).toEqual("User created successfully.");
- done();
- });
- })
- });
-});
+ .expect('Content-Type', /json/)
+
+ expect(res.res.statusMessage).toEqual("User created successfully.");
+ expect(res.body._id).toBeUndefined()
+ })
+ });
+})
diff --git a/packages/server/src/api/routes/tests/view.spec.js b/packages/server/src/api/routes/tests/view.spec.js
index 5e1811bf7..e2aeececc 100644
--- a/packages/server/src/api/routes/tests/view.spec.js
+++ b/packages/server/src/api/routes/tests/view.spec.js
@@ -1,78 +1,73 @@
-const supertest = require("supertest");
-const app = require("../../../app");
-const { createInstanceDatabase, createModel, destroyDatabase } = require("./couchTestUtils");
-
-
-const TEST_INSTANCE_ID = "testing-123";
+const {
+ createClientDatabase,
+ createApplication,
+ createInstance,
+ createModel,
+ supertest,
+ defaultHeaders
+} = require("./couchTestUtils")
describe("/views", () => {
- let request;
- let server;
- let db;
+ let request
+ let server
+ let app
+ let instance
+ let model
beforeAll(async () => {
- server = app;
- request = supertest(server);
- });
+ ({ request, server } = await supertest())
+ await createClientDatabase(request)
+ app = await createApplication(request)
+ })
+
+ beforeEach(async () => {
+ instance = await createInstance(request, app._id)
+ })
afterAll(async () => {
- server.close();
+ server.close()
})
- describe("create", () => {
- beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- });
+ const createView = async () =>
+ await request
+ .post(`/api/${instance._id}/views`)
+ .send({
+ name: "TestView",
+ map: `function(doc) {
+ if (doc.id) {
+ emit(doc.name, doc._id);
+ }
+ }`,
+ reduce: `function(keys, values) { }`
+ })
+ .set(defaultHeaders)
+ .expect('Content-Type', /json/)
+ .expect(200)
- afterEach(async () => {
- db && await db.destroy();
- });
+ describe("create", () => {
- it("returns a success message when the view is successfully created", done => {
- request
- .post(`/api/${TEST_INSTANCE_ID}/views`)
- .send({
- name: "TestView",
- map: `function(doc) {
- if (doc.id) {
- emit(doc.name, doc._id);
- }
- }`,
- reduce: `function(keys, values) { }`
- })
- .set("Accept", "application/json")
- .expect('Content-Type', /json/)
- .expect(200)
- .end(async (err, res) => {
- expect(res.body.message).toEqual("View TestView created successfully.");
- expect(res.body.id).toEqual("_design/database");
- done();
- });
- })
- });
+ it("returns a success message when the view is successfully created", async () => {
+ const res = await createView()
+ expect(res.res.statusMessage).toEqual("View TestView created successfully.");
+ expect(res.body.name).toEqual("TestView");
+ })
+ });
describe("fetch", () => {
- let db;
beforeEach(async () => {
- db = await createInstanceDatabase(TEST_INSTANCE_ID);
- await createModel(TEST_INSTANCE_ID);
+ model = await createModel(request, instance._id);
});
- afterEach(async () => {
- await db.destroy();
- });
-
- it("returns a list of all the views that exist in the instance database", done => {
- request
- .get(`/api/${TEST_INSTANCE_ID}/views`)
- .set("Accept", "application/json")
+ it("should only return custom views", async () => {
+ const view = await createView()
+ const res = await request
+ .get(`/api/${instance._id}/views`)
+ .set(defaultHeaders)
.expect('Content-Type', /json/)
.expect(200)
- .end(async (_, res) => {
- expect(res.body.by_type).toBeDefined();
- done();
- });
- })
- });
+ expect(res.body.length).toBe(1)
+ expect(res.body.find(v => v.name === view.body.name)).toBeDefined()
+ })
+ });
});
diff --git a/packages/server/src/api/routes/user.js b/packages/server/src/api/routes/user.js
index 53cab6aa1..61f4a096f 100644
--- a/packages/server/src/api/routes/user.js
+++ b/packages/server/src/api/routes/user.js
@@ -5,7 +5,8 @@ const router = Router()
router
.get("/api/:instanceId/users", controller.fetch)
- .post("/api/:appId/:instanceId/users", controller.create)
- .delete("/api/:instanceId/users/:userId", controller.destroy)
+ .get("/api/:instanceId/users/:username", controller.find)
+ .post("/api/:instanceId/users", controller.create)
+ .delete("/api/:instanceId/users/:username", controller.destroy)
module.exports = router
diff --git a/packages/server/src/app.js b/packages/server/src/app.js
index 2174d4cef..3c1256f83 100644
--- a/packages/server/src/app.js
+++ b/packages/server/src/app.js
@@ -2,14 +2,30 @@ const Koa = require("koa")
const logger = require("koa-logger")
const api = require("./api")
const koaBody = require("koa-body")
+const env = require("./environment")
+const http = require("http")
const app = new Koa()
// set up top level koa middleware
app.use(koaBody({ multipart: true }))
-app.use(logger())
+
+if (env.LOGGER !== "off") app.use(logger())
// api routes
app.use(api.routes())
-module.exports = app.listen(process.env.PORT || 4001)
+module.exports = async port => {
+ port = port || env.PORT || 4001
+ const server = http.createServer(app.callback())
+ return new Promise((resolve, reject) => {
+ server.on("error", e => {
+ if (e.code === "EADDRINUSE") {
+ reject(e)
+ }
+ })
+ server.listen({ port }, () => {
+ resolve(server)
+ })
+ })
+}
diff --git a/packages/server/src/db/client.js b/packages/server/src/db/client.js
index fcb7cadec..f2c090b56 100644
--- a/packages/server/src/db/client.js
+++ b/packages/server/src/db/client.js
@@ -1,11 +1,16 @@
const PouchDB = require("pouchdb")
const allDbs = require("pouchdb-all-dbs")
const { budibaseAppsDir } = require("../utilities/budibaseDir")
+const env = require("../environment")
-const COUCH_DB_URL = process.env.COUCH_DB_URL || `leveldb://${budibaseAppsDir()}/`
+const COUCH_DB_URL = env.COUCH_DB_URL || `leveldb://${budibaseAppsDir().replace(/\\/g, "/")}/.data/`
+const isInMemory = env.NODE_ENV === "jest"
+
+if (isInMemory) PouchDB.plugin(require("pouchdb-adapter-memory"))
const Pouch = PouchDB.defaults({
- prefix: COUCH_DB_URL,
+ prefix: isInMemory ? undefined : COUCH_DB_URL,
+ adapter: isInMemory ? "memory" : undefined,
})
allDbs(Pouch)
diff --git a/packages/server/src/db/clientDb.js b/packages/server/src/db/clientDb.js
new file mode 100644
index 000000000..b85cd4311
--- /dev/null
+++ b/packages/server/src/db/clientDb.js
@@ -0,0 +1,26 @@
+const CouchDB = require("./client")
+
+exports.create = async clientId => {
+ const dbId = exports.name(clientId)
+ const db = new CouchDB(dbId)
+ await db.put({
+ _id: "_design/client",
+ views: {
+ by_type: {
+ map: `function(doc) {
+ emit([doc.type], doc._id)
+ }`,
+ },
+ },
+ })
+ return db
+}
+
+exports.destroy = async function(clientId) {
+ const dbId = exports.name(clientId)
+ await new CouchDB(dbId).destroy()
+}
+
+exports.name = function(clientId) {
+ return `client_${clientId}`
+}
diff --git a/packages/server/src/db/initialiseClientDb.js b/packages/server/src/db/initialiseClientDb.js
deleted file mode 100644
index 4fb88c99a..000000000
--- a/packages/server/src/db/initialiseClientDb.js
+++ /dev/null
@@ -1,13 +0,0 @@
-module.exports = async db => {
- const doc = await db.put({
- _id: "_design/client",
- views: {
- by_type: {
- map: `function(doc) {
- emit([doc.type], doc._id)
- }`,
- },
- },
- })
- console.log(doc)
-}
diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js
new file mode 100644
index 000000000..fdf8b9874
--- /dev/null
+++ b/packages/server/src/environment.js
@@ -0,0 +1,11 @@
+module.exports = {
+ CLIENT_ID: process.env.CLIENT_ID,
+ NODE_ENV: process.env.NODE_ENV,
+ JWT_SECRET: process.env.JWT_SECRET,
+ BUDIBASE_DIR: process.env.BUDIBASE_DIR,
+ ADMIN_SECRET: process.env.ADMIN_SECRET,
+ PORT: process.env.PORT,
+ COUCH_DB_URL: process.env.COUCH_DB_URL,
+ SALT_ROUNDS: process.env.SALT_ROUNDS,
+ LOGGER: process.env.LOGGER,
+}
diff --git a/packages/server/src/middleware/authenticated.js b/packages/server/src/middleware/authenticated.js
index 34c9f66d1..43c8f013e 100644
--- a/packages/server/src/middleware/authenticated.js
+++ b/packages/server/src/middleware/authenticated.js
@@ -1,10 +1,23 @@
const jwt = require("jsonwebtoken")
-const STATUS_CODES = require("../utilities/statusCodes");
+const STATUS_CODES = require("../utilities/statusCodes")
+const env = require("../environment")
module.exports = async (ctx, next) => {
- if (ctx.isDev) {
+ const authHeader = ctx.get("Authorization")
+
+ if (
+ authHeader &&
+ authHeader.startsWith("Basic") &&
+ authHeader.split(" ")[1] === env.ADMIN_SECRET
+ ) {
ctx.isAuthenticated = true
- await next();
+ await next()
+ return
+ }
+
+ if (ctx.isDev && ctx.cookies.get("builder:token") === env.ADMIN_SECRET) {
+ ctx.isAuthenticated = true
+ await next()
return
}
diff --git a/packages/server/src/utilities/bcrypt.js b/packages/server/src/utilities/bcrypt.js
index 46cbff392..58a37c06a 100644
--- a/packages/server/src/utilities/bcrypt.js
+++ b/packages/server/src/utilities/bcrypt.js
@@ -1,6 +1,7 @@
const bcrypt = require("bcryptjs")
+const env = require("../environment")
-const SALT_ROUNDS = process.env.SALT_ROUNDS || 10
+const SALT_ROUNDS = env.SALT_ROUNDS || 10
exports.hash = async data => {
const salt = await bcrypt.genSalt(SALT_ROUNDS)
diff --git a/packages/server/src/utilities/budibaseDir.js b/packages/server/src/utilities/budibaseDir.js
index fd531d419..61044b50b 100644
--- a/packages/server/src/utilities/budibaseDir.js
+++ b/packages/server/src/utilities/budibaseDir.js
@@ -1,8 +1,9 @@
const { join } = require("path")
const { homedir, tmpdir } = require("os")
+const env = require("../environment")
module.exports.budibaseAppsDir = function() {
- return process.env.BUDIBASE_DIR || join(homedir(), ".budibase")
+ return env.BUDIBASE_DIR || join(homedir(), ".budibase")
}
module.exports.budibaseTempDir = function() {
diff --git a/packages/server/src/utilities/builder/index.js b/packages/server/src/utilities/builder/index.js
index a62ac5569..7b9a6a69e 100644
--- a/packages/server/src/utilities/builder/index.js
+++ b/packages/server/src/utilities/builder/index.js
@@ -9,6 +9,7 @@ const {
rmdir,
} = require("fs-extra")
const { join, dirname, resolve } = require("path")
+const env = require("../../environment")
const buildPage = require("./buildPage")
const getPages = require("./getPages")
@@ -31,7 +32,7 @@ module.exports.getPackageForBuilder = async (config, application) => {
application,
- clientId: process.env.CLIENT_ID,
+ clientId: env.CLIENT_ID,
}
}
diff --git a/packages/server/src/utilities/initialiseClientDb.js b/packages/server/src/utilities/initialiseClientDb.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock
index 55e6d622d..449463063 100644
--- a/packages/server/yarn.lock
+++ b/packages/server/yarn.lock
@@ -576,6 +576,13 @@ abort-controller@3.0.0:
dependencies:
event-target-shim "^5.0.0"
+abstract-leveldown@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.4.1.tgz#b3bfedb884eb693a12775f0c55e9f0a420ccee64"
+ integrity sha1-s7/tuITraToSd18MVenwpCDM7mQ=
+ dependencies:
+ xtend "~4.0.0"
+
abstract-leveldown@^6.2.1:
version "6.3.0"
resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a"
@@ -4271,6 +4278,11 @@ ltgt@2.2.1, ltgt@^2.1.2:
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5"
integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=
+ltgt@~2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34"
+ integrity sha1-EIUaBtmWS5cReEQcI8nlJpjuzjQ=
+
lunr@^2.3.5:
version "2.3.8"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.8.tgz#a8b89c31f30b5a044b97d2d28e2da191b6ba2072"
@@ -4322,6 +4334,17 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+memdown@1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.2.4.tgz#cd9a34aaf074d53445a271108eb4b8dd4ec0f27f"
+ integrity sha1-zZo0qvB01TRFonEQjrS43U7A8n8=
+ dependencies:
+ abstract-leveldown "2.4.1"
+ functional-red-black-tree "^1.0.1"
+ immediate "^3.2.3"
+ inherits "~2.0.1"
+ ltgt "~2.1.3"
+
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -4905,6 +4928,47 @@ 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=
+pouchdb-adapter-leveldb-core@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-adapter-leveldb-core/-/pouchdb-adapter-leveldb-core-7.2.1.tgz#71bf2a05755689e2b05e78e796003a18ebf65a69"
+ integrity sha512-kwNsaM1pYDVz6LG9z2/7Tfcuw5iZJ5u8IqzjxMAGCfurScMaF4e7IJnVWqAceWSiaCrp91DbCULhrl4SH8iTDg==
+ dependencies:
+ argsarray "0.0.1"
+ buffer-from "1.1.0"
+ double-ended-queue "2.1.0-0"
+ levelup "4.1.0"
+ pouchdb-adapter-utils "7.2.1"
+ pouchdb-binary-utils "7.2.1"
+ pouchdb-collections "7.2.1"
+ pouchdb-errors "7.2.1"
+ pouchdb-json "7.2.1"
+ pouchdb-md5 "7.2.1"
+ pouchdb-merge "7.2.1"
+ pouchdb-utils "7.2.1"
+ sublevel-pouchdb "7.2.1"
+ through2 "3.0.1"
+
+pouchdb-adapter-memory@^7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-adapter-memory/-/pouchdb-adapter-memory-7.2.1.tgz#70341b54093b6bda3ab6e78482c8d00b906178e9"
+ integrity sha512-W4+9+xol95NIdDlk2KVxhv81QWRx/P4L9CPGdh7nqGtzuhVbvqMEqZN24XauIoBaaDy1LLkCyXMvChNt3GHBRQ==
+ dependencies:
+ memdown "1.2.4"
+ pouchdb-adapter-leveldb-core "7.2.1"
+ pouchdb-utils "7.2.1"
+
+pouchdb-adapter-utils@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-adapter-utils/-/pouchdb-adapter-utils-7.2.1.tgz#d2583bc5c6bfcd6cf0d20acd54cb51683a196d37"
+ integrity sha512-asMAhH6mJRgz6JFEvaS/gMcfWR9pCM+DLPzzIN5vSAm8jUEaMApCONx86xhBwVgzAJ8aVzrG11J9D5iJlM7LSQ==
+ dependencies:
+ pouchdb-binary-utils "7.2.1"
+ pouchdb-collections "7.2.1"
+ pouchdb-errors "7.2.1"
+ pouchdb-md5 "7.2.1"
+ pouchdb-merge "7.2.1"
+ pouchdb-utils "7.2.1"
+
pouchdb-all-dbs@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pouchdb-all-dbs/-/pouchdb-all-dbs-1.0.2.tgz#8fa1aa4b01665e00e0da9c61bf6dbb99eca05d3c"
@@ -4916,6 +4980,45 @@ pouchdb-all-dbs@^1.0.2:
pouchdb-promise "5.4.3"
tiny-queue "^0.2.0"
+pouchdb-binary-utils@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-7.2.1.tgz#ad23ed63d09699e7e6244f846b5cf07c6d9d4b8b"
+ integrity sha512-kbzOOYti/3d8s2bQY5EfJVd7c9E84q4oEpr1M8fOOHKnINZFteKkZQywD4roblUnew0Obyhvozif4LAr3CMZFg==
+ dependencies:
+ buffer-from "1.1.0"
+
+pouchdb-collections@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-7.2.1.tgz#768c2c578b22eda9ac0c92a4b1106d18f3c113fb"
+ integrity sha512-cqe3GY3wDq2j59tnh+5ZV0bZj1O+YWiBz4qM7HEcgrEXnc29ADvXXPp71tmcpZUCR39bzLKyYtadAQu7FpOeOA==
+
+pouchdb-errors@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-7.2.1.tgz#798f5279a0d363d6b93c97a1b65ee903f61af143"
+ integrity sha512-/tBP+eWY6a62UoZnJ6JJlNmbNpNS5FgVimkqwLMrFQkXpbJlhshYDeJ5PHR0W3Rlfc54GMZC7m4KhJt9kG/CkA==
+ dependencies:
+ inherits "2.0.4"
+
+pouchdb-json@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-json/-/pouchdb-json-7.2.1.tgz#41836bdffed1d1b6207793f0b26bf771105c0c61"
+ integrity sha512-YGRX/qDl+iEX2vz23kzBtMoH0hpb9xASKnEGZPH76BTDq4RQ+eUOxyXU9E1fPdQhsq8+0pcEQN7VCnFEdQ7MUQ==
+ dependencies:
+ vuvuzela "1.0.3"
+
+pouchdb-md5@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-7.2.1.tgz#2b057b148b3f31491d77c4dd6b6139af31b07f66"
+ integrity sha512-TJqGtNguctPiSai5b4+oTPi9oOcxSbNolkUtxRBxklf8kw+PNsDUi1H0DIFmA57n0qHCU19PXdbEVYlUhv/PAA==
+ dependencies:
+ pouchdb-binary-utils "7.2.1"
+ spark-md5 "3.0.0"
+
+pouchdb-merge@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-7.2.1.tgz#d9301a4e92ccb14347ef8cc6a01caa63e3950fcd"
+ integrity sha512-TgxXPw1sZERwihoWSzLIdvn5MP1YKhYNaB0UuvYjboK+WUpCLh5WEeNTJi6WwUD9Yoc66QxP9D3qmfNEjd1BHQ==
+
pouchdb-promise@5.4.3:
version "5.4.3"
resolved "https://registry.yarnpkg.com/pouchdb-promise/-/pouchdb-promise-5.4.3.tgz#331d670b1989d5a03f268811214f27f54150cb2b"
@@ -4923,6 +5026,20 @@ pouchdb-promise@5.4.3:
dependencies:
lie "3.0.4"
+pouchdb-utils@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-7.2.1.tgz#5dec1c53c8ecba717e5762311e9a1def2d4ebf9c"
+ integrity sha512-ZInfRpKtJ2HwLz2Dv3NEona9khvGud0rWzvQGwUs1zoaOoSB5XxK3ui5s5fLpBrONgz0WcTB49msOUq4oAUzFg==
+ dependencies:
+ argsarray "0.0.1"
+ clone-buffer "1.0.0"
+ immediate "3.0.6"
+ inherits "2.0.4"
+ pouchdb-collections "7.2.1"
+ pouchdb-errors "7.2.1"
+ pouchdb-md5 "7.2.1"
+ uuid "3.3.3"
+
pouchdb@^7.2.1:
version "7.2.1"
resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-7.2.1.tgz#619e3d5c2463ddd94a4b1bf40d44408c46e9de79"
@@ -5888,6 +6005,16 @@ strip-json-comments@~2.0.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+sublevel-pouchdb@7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/sublevel-pouchdb/-/sublevel-pouchdb-7.2.1.tgz#ce3ec06c91ee5afb5ab1bb7abbb905fd4dcc8c38"
+ integrity sha512-pliYcLDubhpe8ONw3P09CehULjuNopl6ybj6N0YudOg+FidqEYgJUgN/1n7ZqVrcXCDHws9g6lN1srlQta5/XQ==
+ dependencies:
+ inherits "2.0.4"
+ level-codec "9.0.1"
+ ltgt "2.2.1"
+ readable-stream "1.0.33"
+
sumchecker@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42"