From bc94f20794428d58ba4ddca3dfaa7702df318e1f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 11 Nov 2022 11:57:50 +0000 Subject: [PATCH] Typescript conversions - trying to get all of context/db layer into TS. --- ...{FunctionContext.js => FunctionContext.ts} | 14 ++-- .../{deprovision.js => deprovision.ts} | 68 ++++++++++--------- packages/backend-core/src/context/index.ts | 6 ++ .../src/db/{conversions.js => conversions.ts} | 21 +++--- packages/backend-core/src/index.ts | 2 +- packages/backend-core/src/users.ts | 2 +- .../src/api/controllers/deploy/index.ts | 38 ++++------- packages/server/src/automations/utils.ts | 21 +++--- packages/types/src/documents/pouch.ts | 2 +- 9 files changed, 85 insertions(+), 89 deletions(-) rename packages/backend-core/src/context/{FunctionContext.js => FunctionContext.ts} (79%) rename packages/backend-core/src/context/{deprovision.js => deprovision.ts} (64%) rename packages/backend-core/src/db/{conversions.js => conversions.ts} (68%) diff --git a/packages/backend-core/src/context/FunctionContext.js b/packages/backend-core/src/context/FunctionContext.ts similarity index 79% rename from packages/backend-core/src/context/FunctionContext.js rename to packages/backend-core/src/context/FunctionContext.ts index c0ed34fe78..1010f585ef 100644 --- a/packages/backend-core/src/context/FunctionContext.js +++ b/packages/backend-core/src/context/FunctionContext.ts @@ -1,10 +1,10 @@ -const cls = require("../clshooked") -const { newid } = require("../hashing") +import cls from "../clshooked" +import { newid } from "../hashing" const REQUEST_ID_KEY = "requestId" const MAIN_CTX = cls.createNamespace("main") -function getContextStorage(namespace) { +function getContextStorage(namespace: any) { if (namespace && namespace.active) { let contextData = namespace.active delete contextData.id @@ -15,7 +15,7 @@ function getContextStorage(namespace) { } class FunctionContext { - static run(callback) { + static run(callback: any) { return MAIN_CTX.runAndReturn(async () => { const namespaceId = newid() MAIN_CTX.set(REQUEST_ID_KEY, namespaceId) @@ -26,13 +26,13 @@ class FunctionContext { }) } - static setOnContext(key, value) { + static setOnContext(key: string, value: any) { const namespaceId = MAIN_CTX.get(REQUEST_ID_KEY) const namespace = cls.getNamespace(namespaceId) namespace.set(key, value) } - static getFromContext(key) { + static getFromContext(key: string) { const namespaceId = MAIN_CTX.get(REQUEST_ID_KEY) const namespace = cls.getNamespace(namespaceId) const context = getContextStorage(namespace) @@ -44,4 +44,4 @@ class FunctionContext { } } -module.exports = FunctionContext +export = FunctionContext diff --git a/packages/backend-core/src/context/deprovision.js b/packages/backend-core/src/context/deprovision.ts similarity index 64% rename from packages/backend-core/src/context/deprovision.js rename to packages/backend-core/src/context/deprovision.ts index ba3c2d8449..179c7f407a 100644 --- a/packages/backend-core/src/context/deprovision.js +++ b/packages/backend-core/src/context/deprovision.ts @@ -1,16 +1,20 @@ -const { getGlobalUserParams, getAllApps } = require("../db/utils") -const { doWithDB } = require("../db") -const { doWithGlobalDB } = require("../tenancy") -const { StaticDatabases } = require("../db/constants") +import { getGlobalUserParams, getAllApps } from "../db/utils" +import { doWithDB } from "../db" +import { doWithGlobalDB } from "../tenancy" +import { StaticDatabases } from "../db/constants" +import { PouchLike } from "../couch" +import { User } from "@budibase/types" const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name -const removeTenantFromInfoDB = async tenantId => { +async function removeTenantFromInfoDB(tenantId: string) { try { - await doWithDB(PLATFORM_INFO_DB, async infoDb => { + await doWithDB(PLATFORM_INFO_DB, async (infoDb: PouchLike) => { let tenants = await infoDb.get(TENANT_DOC) - tenants.tenantIds = tenants.tenantIds.filter(id => id !== tenantId) + tenants.tenantIds = tenants.tenantIds.filter( + (id: string) => id !== tenantId + ) await infoDb.put(tenants) }) @@ -20,32 +24,15 @@ const removeTenantFromInfoDB = async tenantId => { } } -exports.removeUserFromInfoDB = async dbUser => { - await doWithDB(PLATFORM_INFO_DB, async infoDb => { - 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 => { - return doWithGlobalDB(tenantId, async db => { +async function removeUsersFromInfoDB(tenantId: string) { + return doWithGlobalDB(tenantId, async (db: PouchLike) => { try { const allUsers = await db.allDocs( getGlobalUserParams(null, { include_docs: true, }) ) - await doWithDB(PLATFORM_INFO_DB, async infoDb => { + await doWithDB(PLATFORM_INFO_DB, async (infoDb: PouchLike) => { const allEmails = allUsers.rows.map(row => row.doc.email) // get the id docs let keys = allUsers.rows.map(row => row.id) @@ -71,8 +58,8 @@ const removeUsersFromInfoDB = async tenantId => { }) } -const removeGlobalDB = async tenantId => { - return doWithGlobalDB(tenantId, async db => { +async function removeGlobalDB(tenantId: string) { + return doWithGlobalDB(tenantId, async (db: PouchLike) => { try { await db.destroy() } catch (err) { @@ -82,11 +69,11 @@ const removeGlobalDB = async tenantId => { }) } -const removeTenantApps = async tenantId => { +async function removeTenantApps(tenantId: string) { try { const apps = await getAllApps({ all: true }) const destroyPromises = apps.map(app => - doWithDB(app.appId, db => db.destroy()) + doWithDB(app.appId, (db: PouchLike) => db.destroy()) ) await Promise.allSettled(destroyPromises) } catch (err) { @@ -95,8 +82,25 @@ const removeTenantApps = async tenantId => { } } +export async function removeUserFromInfoDB(dbUser: User) { + await doWithDB(PLATFORM_INFO_DB, async (infoDb: PouchLike) => { + 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) + }) +} + // can't live in tenancy package due to circular dependency on db/utils -exports.deleteTenant = async tenantId => { +export async function deleteTenant(tenantId: string) { await removeTenantFromInfoDB(tenantId) await removeUsersFromInfoDB(tenantId) await removeGlobalDB(tenantId) diff --git a/packages/backend-core/src/context/index.ts b/packages/backend-core/src/context/index.ts index e8813c5a2f..63b57a1b6e 100644 --- a/packages/backend-core/src/context/index.ts +++ b/packages/backend-core/src/context/index.ts @@ -203,6 +203,9 @@ export function getAppDB(opts?: any): PouchLike { */ export function getProdAppDB(opts?: any): PouchLike { const appId = getAppId() + if (!appId) { + throw new Error("Unable to retrieve prod DB - no app ID.") + } return new PouchLike(getProdAppID(appId), opts) } @@ -212,5 +215,8 @@ export function getProdAppDB(opts?: any): PouchLike { */ export function getDevAppDB(opts?: any): PouchLike { const appId = getAppId() + if (!appId) { + throw new Error("Unable to retrieve dev DB - no app ID.") + } return new PouchLike(getDevelopmentAppID(appId), opts) } diff --git a/packages/backend-core/src/db/conversions.js b/packages/backend-core/src/db/conversions.ts similarity index 68% rename from packages/backend-core/src/db/conversions.js rename to packages/backend-core/src/db/conversions.ts index 5b1a785ecc..48eaf31844 100644 --- a/packages/backend-core/src/db/conversions.js +++ b/packages/backend-core/src/db/conversions.ts @@ -1,32 +1,33 @@ +import { APP_DEV_PREFIX, APP_PREFIX } from "./constants" +import { App } from "@budibase/types" const NO_APP_ERROR = "No app provided" -const { APP_DEV_PREFIX, APP_PREFIX } = require("./constants") -exports.isDevAppID = appId => { +export function isDevAppID(appId?: string) { if (!appId) { throw NO_APP_ERROR } return appId.startsWith(APP_DEV_PREFIX) } -exports.isProdAppID = appId => { +export function isProdAppID(appId?: string) { if (!appId) { throw NO_APP_ERROR } - return appId.startsWith(APP_PREFIX) && !exports.isDevAppID(appId) + return appId.startsWith(APP_PREFIX) && !isDevAppID(appId) } -exports.isDevApp = app => { +export function isDevApp(app: App) { if (!app) { throw NO_APP_ERROR } - return exports.isDevAppID(app.appId) + return isDevAppID(app.appId) } /** * Generates a development app ID from a real app ID. * @returns {string} the dev app ID which can be used for dev database. */ -exports.getDevelopmentAppID = appId => { +export function getDevelopmentAppID(appId: string) { if (!appId || appId.startsWith(APP_DEV_PREFIX)) { return appId } @@ -36,12 +37,12 @@ exports.getDevelopmentAppID = appId => { const rest = split.join(APP_PREFIX) return `${APP_DEV_PREFIX}${rest}` } -exports.getDevAppID = exports.getDevelopmentAppID +export const getDevAppID = getDevelopmentAppID /** * Convert a development app ID to a deployed app ID. */ -exports.getProdAppID = appId => { +export function getProdAppID(appId: string) { if (!appId || !appId.startsWith(APP_DEV_PREFIX)) { return appId } @@ -52,7 +53,7 @@ exports.getProdAppID = appId => { return `${APP_PREFIX}${rest}` } -exports.extractAppUUID = id => { +export function extractAppUUID(id: string) { const split = id?.split("_") || [] return split.length ? split[split.length - 1] : null } diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index 06997ced90..b45248abc2 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -11,7 +11,7 @@ import env from "./environment" import tenancy from "./tenancy" import featureFlags from "./featureFlags" import * as sessions from "./security/sessions" -import deprovisioning from "./context/deprovision" +import * as deprovisioning from "./context/deprovision" import auth from "./auth" import constants from "./constants" import * as dbConstants from "./db/constants" diff --git a/packages/backend-core/src/users.ts b/packages/backend-core/src/users.ts index a38debfc19..13e8f8d36e 100644 --- a/packages/backend-core/src/users.ts +++ b/packages/backend-core/src/users.ts @@ -68,7 +68,7 @@ export const getGlobalUserByAppPage = (appId: string, user: User) => { if (!user) { return } - return generateAppUserID(getProdAppID(appId), user._id!) + return generateAppUserID(getProdAppID(appId)!, user._id!) } /** diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index cb4534a1a5..a87e7fbd7d 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -1,23 +1,11 @@ import Deployment from "./Deployment" -import { - getDevelopmentAppID, - getProdAppID, - Replication, -} from "@budibase/backend-core/db" +import { context, db as dbCore, events, cache } from "@budibase/backend-core" import { DocumentType, getAutomationParams } from "../../../db/utils" import { clearMetadata, disableAllCrons, enableCronTrigger, } from "../../../automations/utils" -import { app as appCache } from "@budibase/backend-core/cache" -import { - getAppDB, - getAppId, - getDevAppDB, - getProdAppDB, -} from "@budibase/backend-core/context" -import { events } from "@budibase/backend-core" import { backups } from "@budibase/pro" import { AppBackupTrigger } from "@budibase/types" @@ -49,7 +37,7 @@ async function checkAllDeployments(deployments: any) { async function storeDeploymentHistory(deployment: any) { const deploymentJSON = deployment.getJSON() - const db = getAppDB() + const db = context.getAppDB() let deploymentDoc try { @@ -77,7 +65,7 @@ async function storeDeploymentHistory(deployment: any) { } async function initDeployedApp(prodAppId: any) { - const db = getProdAppDB() + const db = context.getProdAppDB() console.log("Reading automation docs") const automations = ( await db.allDocs( @@ -103,9 +91,9 @@ async function initDeployedApp(prodAppId: any) { async function deployApp(deployment: any, userId: string) { let replication try { - const appId = getAppId() - const devAppId = getDevelopmentAppID(appId) - const productionAppId = getProdAppID(appId) + const appId = context.getAppId()! + const devAppId = dbCore.getDevelopmentAppID(appId) + const productionAppId = dbCore.getProdAppID(appId) // don't try this if feature isn't allowed, will error if (await backups.isEnabled()) { @@ -122,8 +110,8 @@ async function deployApp(deployment: any, userId: string) { source: devAppId, target: productionAppId, } - replication = new Replication(config) - const devDb = getDevAppDB() + replication = new dbCore.Replication(config) + const devDb = context.getDevAppDB() console.log("Compacting development DB") await devDb.compact() console.log("Replication object created") @@ -131,7 +119,7 @@ async function deployApp(deployment: any, userId: string) { console.log("replication complete.. replacing app meta doc") // app metadata is excluded as it is likely to be in conflict // replicate the app metadata document manually - const db = getProdAppDB() + const db = context.getProdAppDB() const appDoc = await devDb.get(DocumentType.APP_METADATA) try { const prodAppDoc = await db.get(DocumentType.APP_METADATA) @@ -147,7 +135,7 @@ async function deployApp(deployment: any, userId: string) { // remove automation errors if they exist delete appDoc.automationErrors await db.put(appDoc) - await appCache.invalidateAppMetadata(productionAppId) + await cache.app.invalidateAppMetadata(productionAppId) console.log("New app doc written successfully.") await initDeployedApp(productionAppId) console.log("Deployed app initialised, setting deployment to successful") @@ -170,7 +158,7 @@ async function deployApp(deployment: any, userId: string) { export async function fetchDeployments(ctx: any) { try { - const db = getAppDB() + const db = context.getAppDB() const deploymentDoc = await db.get(DocumentType.DEPLOYMENTS) const { updated, deployments } = await checkAllDeployments(deploymentDoc) if (updated) { @@ -184,7 +172,7 @@ export async function fetchDeployments(ctx: any) { export async function deploymentProgress(ctx: any) { try { - const db = getAppDB() + const db = context.getAppDB() const deploymentDoc = await db.get(DocumentType.DEPLOYMENTS) ctx.body = deploymentDoc[ctx.params.deploymentId] } catch (err) { @@ -197,7 +185,7 @@ export async function deploymentProgress(ctx: any) { const isFirstDeploy = async () => { try { - const db = getProdAppDB() + const db = context.getProdAppDB() await db.get(DocumentType.APP_METADATA) } catch (e: any) { if (e.status === 404) { diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts index af4bb8d3af..5296a0fa50 100644 --- a/packages/server/src/automations/utils.ts +++ b/packages/server/src/automations/utils.ts @@ -4,15 +4,9 @@ import { automationQueue } from "./bullboard" import newid from "../db/newid" import { updateEntityMetadata } from "../utilities" import { MetadataTypes } from "../constants" -import { getProdAppID, doWithDB } from "@budibase/backend-core/db" +import { db as dbCore, context } from "@budibase/backend-core" import { getAutomationMetadataParams } from "../db/utils" import { cloneDeep } from "lodash/fp" -import { - getAppDB, - getAppId, - getProdAppDB, -} from "@budibase/backend-core/context" -import { context } from "@budibase/backend-core" import { quotas } from "@budibase/pro" import { Automation, WebhookActionType } from "@budibase/types" import sdk from "../sdk" @@ -102,7 +96,7 @@ export async function disableCronById(jobId: number | string) { } export async function clearMetadata() { - const db = getProdAppDB() + const db = context.getProdAppDB() const automationMetadata = ( await db.allDocs( getAutomationMetadataParams({ @@ -157,7 +151,7 @@ export async function enableCronTrigger(appId: any, automation: Automation) { // 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 - await doWithDB(appId, async (db: any) => { + await dbCore.doWithDB(appId, async (db: any) => { const response = await db.put(automation) automation._id = response.id automation._rev = response.rev @@ -175,7 +169,10 @@ export async function enableCronTrigger(appId: any, automation: Automation) { * written to DB (this does not write to DB as it would be wasteful to repeat). */ export async function checkForWebhooks({ oldAuto, newAuto }: any) { - const appId = getAppId() + const appId = context.getAppId() + if (!appId) { + throw new Error("Unable to check webhooks - no app ID in context.") + } const oldTrigger = oldAuto ? oldAuto.definition.trigger : null const newTrigger = newAuto ? newAuto.definition.trigger : null const triggerChanged = @@ -194,7 +191,7 @@ export async function checkForWebhooks({ oldAuto, newAuto }: any) { oldTrigger.webhookId ) { try { - let db = getAppDB() + let db = context.getAppDB() // need to get the webhook to get the rev const webhook = await db.get(oldTrigger.webhookId) // might be updating - reset the inputs to remove the URLs @@ -224,7 +221,7 @@ export async function checkForWebhooks({ oldAuto, newAuto }: any) { // the app ID has to be development for this endpoint // it can only be used when building the app // but the trigger endpoint will always be used in production - const prodAppId = getProdAppID(appId) + const prodAppId = dbCore.getProdAppID(appId) newTrigger.inputs = { schemaUrl: `api/webhooks/schema/${appId}/${id}`, triggerUrl: `api/webhooks/trigger/${prodAppId}/${id}`, diff --git a/packages/types/src/documents/pouch.ts b/packages/types/src/documents/pouch.ts index fa66bfa57f..269d8cbbae 100644 --- a/packages/types/src/documents/pouch.ts +++ b/packages/types/src/documents/pouch.ts @@ -8,7 +8,7 @@ export interface RowResponse { key: string error: string value: RowValue - doc?: T + doc?: T | any } export interface AllDocsResponse {