From e4fd2c94d41ba2b8e5f1eec19700d8758af97e8d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Nov 2024 16:03:53 +0000 Subject: [PATCH 01/13] Api key, application and analytics API typing. --- .../server/src/api/controllers/analytics.ts | 14 ++++-- .../server/src/api/controllers/apikeys.ts | 23 +++++++--- .../server/src/api/controllers/application.ts | 44 ++++++++++++++----- .../src/api/controllers/deploy/index.ts | 11 ++++- .../server/src/sdk/app/applications/sync.ts | 2 +- packages/types/src/api/web/analytics.ts | 4 ++ packages/types/src/api/web/apikeys.ts | 10 +++++ packages/types/src/api/web/application.ts | 25 +++++++++++ packages/types/src/api/web/deployment.ts | 3 ++ packages/types/src/api/web/index.ts | 2 + .../types/src/documents/app/deployment.ts | 7 +++ packages/types/src/documents/app/index.ts | 1 + .../types/src/documents/global/apikeys.ts | 5 +++ packages/types/src/documents/global/index.ts | 1 + 14 files changed, 126 insertions(+), 26 deletions(-) create mode 100644 packages/types/src/api/web/apikeys.ts create mode 100644 packages/types/src/api/web/deployment.ts create mode 100644 packages/types/src/documents/app/deployment.ts create mode 100644 packages/types/src/documents/global/apikeys.ts diff --git a/packages/server/src/api/controllers/analytics.ts b/packages/server/src/api/controllers/analytics.ts index f60c7b0961f..8c87af72515 100644 --- a/packages/server/src/api/controllers/analytics.ts +++ b/packages/server/src/api/controllers/analytics.ts @@ -1,16 +1,22 @@ import { events, context } from "@budibase/backend-core" -import { AnalyticsPingRequest, App, PingSource } from "@budibase/types" +import { + AnalyticsPingRequest, + App, + PingSource, + Ctx, + AnalyticsEnabledResponse, +} from "@budibase/types" import { DocumentType, isDevAppID } from "../../db/utils" -export const isEnabled = async (ctx: any) => { +export const isEnabled = async (ctx: Ctx) => { const enabled = await events.analytics.enabled() ctx.body = { enabled, } } -export const ping = async (ctx: any) => { - const body = ctx.request.body as AnalyticsPingRequest +export const ping = async (ctx: Ctx) => { + const body = ctx.request.body switch (body.source) { case PingSource.APP: { diff --git a/packages/server/src/api/controllers/apikeys.ts b/packages/server/src/api/controllers/apikeys.ts index 2a02078483a..8f841cd4573 100644 --- a/packages/server/src/api/controllers/apikeys.ts +++ b/packages/server/src/api/controllers/apikeys.ts @@ -1,18 +1,25 @@ import { db as dbCore, tenancy } from "@budibase/backend-core" -import { BBContext, Document } from "@budibase/types" +import { + Document, + UserCtx, + ApiKeyDoc, + ApiKeyFetchResponse, + ApiKeyUpdateRequest, + ApiKeyUpdateResponse, +} from "@budibase/types" const KEYS_DOC = dbCore.StaticDatabases.GLOBAL.docs.apiKeys async function getBuilderMainDoc() { const db = tenancy.getGlobalDB() - try { - return await db.get(KEYS_DOC) - } catch (err) { - // doesn't exist yet, nothing to get + const doc = await db.tryGet(KEYS_DOC) + if (!doc) { return { _id: KEYS_DOC, + apiKeys: {}, } } + return doc } async function setBuilderMainDoc(doc: Document) { @@ -22,7 +29,7 @@ async function setBuilderMainDoc(doc: Document) { return db.put(doc) } -export async function fetch(ctx: BBContext) { +export async function fetch(ctx: UserCtx) { try { const mainDoc = await getBuilderMainDoc() ctx.body = mainDoc.apiKeys ? mainDoc.apiKeys : {} @@ -32,7 +39,9 @@ export async function fetch(ctx: BBContext) { } } -export async function update(ctx: BBContext) { +export async function update( + ctx: UserCtx +) { const key = ctx.params.key const value = ctx.request.body.value diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 101257c3216..9170ba54c6d 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -59,6 +59,16 @@ import { BBReferenceFieldSubType, Row, BBRequest, + SyncAppResponse, + CreateAppResponse, + FetchAppsResponse, + UpdateAppClientResponse, + RevertAppClientResponse, + DestroyAppResponse, + ImportToUpdateAppRequest, + ImportToUpdateAppResponse, + SetRevertableAppVersionRequest, + SetRevertableAppVersionResponse, } from "@budibase/types" import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts" import sdk from "../../sdk" @@ -166,7 +176,7 @@ async function createInstance(appId: string, template: AppTemplate) { return { _id: appId } } -export const addSampleData = async (ctx: UserCtx) => { +export const addSampleData = async (ctx: UserCtx) => { const db = context.getAppDB() try { @@ -182,7 +192,7 @@ export const addSampleData = async (ctx: UserCtx) => { ctx.status = 200 } -export async function fetch(ctx: UserCtx) { +export async function fetch(ctx: UserCtx) { ctx.body = await sdk.applications.fetch( ctx.query.status as AppStatus, ctx.user @@ -242,7 +252,9 @@ export async function fetchAppPackage( } } -async function performAppCreate(ctx: UserCtx) { +async function performAppCreate( + ctx: UserCtx +) { const apps = (await dbCore.getAllApps({ dev: true })) as App[] const { body } = ctx.request const { name, url, encryptionPassword, templateKey } = body @@ -510,7 +522,9 @@ async function appPostCreate(ctx: UserCtx, app: App) { } } -export async function create(ctx: UserCtx) { +export async function create( + ctx: UserCtx +) { const newApplication = await quotas.addApp(() => performAppCreate(ctx)) await appPostCreate(ctx, newApplication) await cache.bustCache(cache.CacheKey.CHECKLIST) @@ -553,7 +567,9 @@ export async function update( }) } -export async function updateClient(ctx: UserCtx) { +export async function updateClient( + ctx: UserCtx +) { // Get current app version const application = await sdk.applications.metadata.get() const currentVersion = application.version @@ -581,7 +597,9 @@ export async function updateClient(ctx: UserCtx) { ctx.body = app } -export async function revertClient(ctx: UserCtx) { +export async function revertClient( + ctx: UserCtx +) { // Check app can be reverted const application = await sdk.applications.metadata.get() if (!application.revertableVersion) { @@ -668,7 +686,7 @@ async function postDestroyApp(ctx: UserCtx) { } } -export async function destroy(ctx: UserCtx) { +export async function destroy(ctx: UserCtx) { await preDestroyApp(ctx) const result = await destroyApp(ctx) await postDestroyApp(ctx) @@ -676,7 +694,7 @@ export async function destroy(ctx: UserCtx) { ctx.body = result } -export async function unpublish(ctx: UserCtx) { +export async function unpublish(ctx: UserCtx) { const prodAppId = dbCore.getProdAppID(ctx.params.appId) const dbExists = await dbCore.dbExists(prodAppId) @@ -692,7 +710,7 @@ export async function unpublish(ctx: UserCtx) { builderSocket?.emitAppUnpublish(ctx) } -export async function sync(ctx: UserCtx) { +export async function sync(ctx: UserCtx) { const appId = ctx.params.appId try { ctx.body = await sdk.applications.syncApp(appId) @@ -701,10 +719,12 @@ export async function sync(ctx: UserCtx) { } } -export async function importToApp(ctx: UserCtx) { +export async function importToApp( + ctx: UserCtx +) { const { appId } = ctx.params const appExport = ctx.request.files?.appExport - const password = ctx.request.body.encryptionPassword as string + const password = ctx.request.body.encryptionPassword if (!appExport) { ctx.throw(400, "Must supply app export to import") } @@ -811,7 +831,7 @@ export async function updateAppPackage( } export async function setRevertableVersion( - ctx: UserCtx<{ revertableVersion: string }, App> + ctx: UserCtx ) { if (!env.isDev()) { ctx.status = 403 diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index 2cf3da3dda1..6a56f7d4687 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -7,7 +7,12 @@ import { enableCronTrigger, } from "../../../automations/utils" import { backups } from "@budibase/pro" -import { App, AppBackupTrigger } from "@budibase/types" +import { + App, + AppBackupTrigger, + PublishAppResponse, + UserCtx, +} from "@budibase/types" import sdk from "../../../sdk" import { builderSocket } from "../../../websockets" @@ -123,7 +128,9 @@ export async function deploymentProgress(ctx: any) { } } -export const publishApp = async function (ctx: any) { +export const publishApp = async function ( + ctx: UserCtx +) { let deployment = new Deployment() console.log("Deployment object created") deployment.setStatus(DeploymentStatus.PENDING) diff --git a/packages/server/src/sdk/app/applications/sync.ts b/packages/server/src/sdk/app/applications/sync.ts index 37450acf1d6..3bbd72c12b4 100644 --- a/packages/server/src/sdk/app/applications/sync.ts +++ b/packages/server/src/sdk/app/applications/sync.ts @@ -113,7 +113,7 @@ export async function syncUsersToAllApps(userIds: string[]) { export async function syncApp( appId: string, opts?: { automationOnly?: boolean } -) { +): Promise<{ message: string }> { if (env.DISABLE_AUTO_PROD_APP_SYNC) { return { message: diff --git a/packages/types/src/api/web/analytics.ts b/packages/types/src/api/web/analytics.ts index 172aeb8dd47..2585964f949 100644 --- a/packages/types/src/api/web/analytics.ts +++ b/packages/types/src/api/web/analytics.ts @@ -3,6 +3,10 @@ export enum PingSource { APP = "app", } +export interface AnalyticsEnabledResponse { + enabled: boolean +} + export interface AnalyticsPingRequest { source: PingSource timezone: string diff --git a/packages/types/src/api/web/apikeys.ts b/packages/types/src/api/web/apikeys.ts new file mode 100644 index 00000000000..e46d0d4db53 --- /dev/null +++ b/packages/types/src/api/web/apikeys.ts @@ -0,0 +1,10 @@ +export type ApiKeyFetchResponse = Record + +export interface ApiKeyUpdateRequest { + value: string +} + +export interface ApiKeyUpdateResponse { + _id: string + _rev: string +} diff --git a/packages/types/src/api/web/application.ts b/packages/types/src/api/web/application.ts index 57422ceabca..168f18ede34 100644 --- a/packages/types/src/api/web/application.ts +++ b/packages/types/src/api/web/application.ts @@ -1,6 +1,10 @@ import type { PlanType } from "../../sdk" import type { Layout, App, Screen } from "../../documents" +export interface SyncAppResponse { + message: string +} + export interface CreateAppRequest { name: string url?: string @@ -12,6 +16,8 @@ export interface CreateAppRequest { file?: { path: string } } +export interface CreateAppResponse extends App {} + export interface DuplicateAppRequest { name: string url?: string @@ -37,6 +43,8 @@ export interface FetchAppPackageResponse { hasLock: boolean } +export type FetchAppsResponse = App[] + export interface PublishResponse { _id: string status: string @@ -45,3 +53,20 @@ export interface PublishResponse { export interface UpdateAppRequest extends Partial {} export interface UpdateAppResponse extends App {} +export interface UpdateAppClientResponse extends App {} +export interface RevertAppClientResponse extends App {} + +export interface DestroyAppResponse { + ok: boolean +} + +export interface ImportToUpdateAppRequest { + encryptionPassword?: string +} +export interface ImportToUpdateAppResponse { + message: string +} + +export interface SetRevertableAppVersionRequest { + revertableVersion: string +} diff --git a/packages/types/src/api/web/deployment.ts b/packages/types/src/api/web/deployment.ts new file mode 100644 index 00000000000..a9a007ed8f1 --- /dev/null +++ b/packages/types/src/api/web/deployment.ts @@ -0,0 +1,3 @@ +import { DeploymentDoc } from "../../documents" + +export interface PublishAppResponse extends DeploymentDoc {} diff --git a/packages/types/src/api/web/index.ts b/packages/types/src/api/web/index.ts index 27d51ce1b78..4c62d97dafe 100644 --- a/packages/types/src/api/web/index.ts +++ b/packages/types/src/api/web/index.ts @@ -16,3 +16,5 @@ export * from "./layout" export * from "./query" export * from "./role" export * from "./plugins" +export * from "./apikeys" +export * from "./deployment" diff --git a/packages/types/src/documents/app/deployment.ts b/packages/types/src/documents/app/deployment.ts new file mode 100644 index 00000000000..63d3aea5f33 --- /dev/null +++ b/packages/types/src/documents/app/deployment.ts @@ -0,0 +1,7 @@ +export interface DeploymentDoc { + _id: string + verification: any + status?: string + err?: any + appUrl?: string +} diff --git a/packages/types/src/documents/app/index.ts b/packages/types/src/documents/app/index.ts index bb94c3b4da7..51c6889f146 100644 --- a/packages/types/src/documents/app/index.ts +++ b/packages/types/src/documents/app/index.ts @@ -18,3 +18,4 @@ export * from "./sqlite" export * from "./snippet" export * from "./rowAction" export * from "./theme" +export * from "./deployment" diff --git a/packages/types/src/documents/global/apikeys.ts b/packages/types/src/documents/global/apikeys.ts new file mode 100644 index 00000000000..4b46f1d3414 --- /dev/null +++ b/packages/types/src/documents/global/apikeys.ts @@ -0,0 +1,5 @@ +import { Document } from "../../" + +export interface ApiKeyDoc extends Document { + apiKeys: Record +} diff --git a/packages/types/src/documents/global/index.ts b/packages/types/src/documents/global/index.ts index b728439dd60..7d2f5a767cd 100644 --- a/packages/types/src/documents/global/index.ts +++ b/packages/types/src/documents/global/index.ts @@ -7,3 +7,4 @@ export * from "./schedule" export * from "./templates" export * from "./environmentVariables" export * from "./auditLogs" +export * from "./apikeys" From b6a28bf56c0ece85c9614f6ac80b9d5db12bbb38 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Nov 2024 16:09:12 +0000 Subject: [PATCH 02/13] app user auth API. --- packages/server/src/api/controllers/auth.ts | 8 ++++---- packages/types/src/api/web/app/user.ts | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/controllers/auth.ts b/packages/server/src/api/controllers/auth.ts index 4ff592534df..6aab688c306 100644 --- a/packages/server/src/api/controllers/auth.ts +++ b/packages/server/src/api/controllers/auth.ts @@ -2,7 +2,7 @@ import { outputProcessing } from "../../utilities/rowProcessor" import { InternalTables } from "../../db/utils" import { getFullUser } from "../../utilities/users" import { roles, context, db as dbCore } from "@budibase/backend-core" -import { ContextUser, Row, UserCtx } from "@budibase/types" +import { AppSelfResponse, ContextUser, Row, UserCtx } from "@budibase/types" import sdk from "../../sdk" import { processUser } from "../../utilities/global" @@ -17,7 +17,7 @@ const addSessionAttributesToUser = (ctx: any) => { } } -export async function fetchSelf(ctx: UserCtx) { +export async function fetchSelf(ctx: UserCtx) { let userId = ctx.user.userId || ctx.user._id /* istanbul ignore next */ if (!userId || !ctx.isAuthenticated) { @@ -45,9 +45,9 @@ export async function fetchSelf(ctx: UserCtx) { try { const userTable = await sdk.tables.getTable(InternalTables.USER_METADATA) // specifically needs to make sure is enriched - ctx.body = await outputProcessing(userTable, user as Row) + ctx.body = (await outputProcessing(userTable, user as Row)) as ContextUser } catch (err: any) { - let response + let response: ContextUser | {} // user didn't exist in app, don't pretend they do if (user.roleId === PUBLIC_ROLE) { response = {} diff --git a/packages/types/src/api/web/app/user.ts b/packages/types/src/api/web/app/user.ts index 7faec83e9cd..f5f20497240 100644 --- a/packages/types/src/api/web/app/user.ts +++ b/packages/types/src/api/web/app/user.ts @@ -7,3 +7,5 @@ export interface SetFlagRequest { flag: string value: any } + +export type AppSelfResponse = ContextUserMetadata | {} From b2b74aa048e82d7d17c5a60b00d42e754d766add Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Nov 2024 17:00:24 +0000 Subject: [PATCH 03/13] Automation API typing. --- .../server/src/api/controllers/automation.ts | 54 +++++++++++++++---- packages/server/src/automations/actions.ts | 4 +- packages/server/src/automations/triggers.ts | 2 +- packages/server/src/automations/utils.ts | 18 ++++--- packages/types/src/api/web/app/automation.ts | 21 ++++++++ packages/types/src/api/web/app/index.ts | 1 + packages/types/src/api/web/automation.ts | 52 +++++++++++++++++- .../src/documents/app/automation/schema.ts | 2 + 8 files changed, 133 insertions(+), 21 deletions(-) create mode 100644 packages/types/src/api/web/app/automation.ts diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index d8bc9d6b21f..89f664853a5 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -13,6 +13,22 @@ import { UserCtx, DeleteAutomationResponse, FetchAutomationResponse, + GetAutomationTriggerDefinitionsResponse, + GetAutomationStepDefinitionsResponse, + GetAutomationActionDefinitionsResponse, + FindAutomationResponse, + UpdateAutomationRequest, + UpdateAutomationResponse, + CreateAutomationRequest, + CreateAutomationResponse, + SearchAutomationLogsRequest, + SearchAutomationLogsResponse, + ClearAutomationLogRequest, + ClearAutomationLogResponse, + TriggerAutomationRequest, + TriggerAutomationResponse, + TestAutomationRequest, + TestAutomationResponse, } from "@budibase/types" import { getActionDefinitions as actionDefs } from "../../automations/actions" import sdk from "../../sdk" @@ -34,7 +50,7 @@ function getTriggerDefinitions() { *************************/ export async function create( - ctx: UserCtx + ctx: UserCtx ) { let automation = ctx.request.body automation.appId = ctx.appId @@ -55,7 +71,9 @@ export async function create( builderSocket?.emitAutomationUpdate(ctx, automation) } -export async function update(ctx: UserCtx) { +export async function update( + ctx: UserCtx +) { let automation = ctx.request.body automation.appId = ctx.appId @@ -80,7 +98,7 @@ export async function fetch(ctx: UserCtx) { ctx.body = { automations } } -export async function find(ctx: UserCtx) { +export async function find(ctx: UserCtx) { ctx.body = await sdk.automations.get(ctx.params.id) } @@ -96,11 +114,15 @@ export async function destroy(ctx: UserCtx) { builderSocket?.emitAutomationDeletion(ctx, automationId) } -export async function logSearch(ctx: UserCtx) { +export async function logSearch( + ctx: UserCtx +) { ctx.body = await automations.logs.logSearch(ctx.request.body) } -export async function clearLogError(ctx: UserCtx) { +export async function clearLogError( + ctx: UserCtx +) { const { automationId, appId } = ctx.request.body await context.doInAppContext(appId, async () => { const db = context.getProdAppDB() @@ -119,15 +141,21 @@ export async function clearLogError(ctx: UserCtx) { }) } -export async function getActionList(ctx: UserCtx) { +export async function getActionList( + ctx: UserCtx +) { ctx.body = await getActionDefinitions() } -export async function getTriggerList(ctx: UserCtx) { +export async function getTriggerList( + ctx: UserCtx +) { ctx.body = getTriggerDefinitions() } -export async function getDefinitionList(ctx: UserCtx) { +export async function getDefinitionList( + ctx: UserCtx +) { ctx.body = { trigger: getTriggerDefinitions(), action: await getActionDefinitions(), @@ -140,7 +168,9 @@ export async function getDefinitionList(ctx: UserCtx) { * * *********************/ -export async function trigger(ctx: UserCtx) { +export async function trigger( + ctx: UserCtx +) { const db = context.getAppDB() let automation = await db.get(ctx.params.id) @@ -185,7 +215,7 @@ export async function trigger(ctx: UserCtx) { } } -function prepareTestInput(input: any) { +function prepareTestInput(input: TestAutomationRequest) { // prepare the test parameters if (input.id && input.row) { input.row._id = input.id @@ -196,7 +226,9 @@ function prepareTestInput(input: any) { return input } -export async function test(ctx: UserCtx) { +export async function test( + ctx: UserCtx +) { const db = context.getAppDB() let automation = await db.get(ctx.params.id) await setTestFlag(automation._id!) diff --git a/packages/server/src/automations/actions.ts b/packages/server/src/automations/actions.ts index a8b69fa7d7f..e91a7086972 100644 --- a/packages/server/src/automations/actions.ts +++ b/packages/server/src/automations/actions.ts @@ -98,7 +98,9 @@ if (env.SELF_HOSTED) { BUILTIN_ACTION_DEFINITIONS["EXECUTE_BASH"] = bash.definition } -export async function getActionDefinitions() { +export async function getActionDefinitions(): Promise< + Record +> { if (await features.flags.isEnabled(FeatureFlag.AUTOMATION_BRANCHING)) { BUILTIN_ACTION_DEFINITIONS["BRANCH"] = branch.definition } diff --git a/packages/server/src/automations/triggers.ts b/packages/server/src/automations/triggers.ts index 70fda1f2377..f422c14acb4 100644 --- a/packages/server/src/automations/triggers.ts +++ b/packages/server/src/automations/triggers.ts @@ -148,7 +148,7 @@ export async function externalTrigger( user?: UserBindings }, { getResponses }: { getResponses?: boolean } = {} -): Promise { +): Promise> { if (automation.disabled) { throw new Error("Automation is disabled") } diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts index 365dc36b682..3eeeae57345 100644 --- a/packages/server/src/automations/utils.ts +++ b/packages/server/src/automations/utils.ts @@ -9,9 +9,11 @@ import { cloneDeep } from "lodash/fp" import { quotas } from "@budibase/pro" import { Automation, + AutomationActionStepId, AutomationJob, AutomationStepDefinition, AutomationTriggerDefinition, + AutomationTriggerStepId, } from "@budibase/types" import { automationsEnabled } from "../features" import { helpers, REBOOT_CRON } from "@budibase/shared-core" @@ -120,19 +122,21 @@ export async function updateTestHistory( ) } -export function removeDeprecated( - definitions: Record< +export function removeDeprecated< + T extends + | Record + | Record +>(definitions: T): T { + const base: Record< string, - AutomationStepDefinition | AutomationTriggerDefinition - > -) { - const base = cloneDeep(definitions) + AutomationTriggerDefinition | AutomationStepDefinition + > = cloneDeep(definitions) for (let key of Object.keys(base)) { if (base[key].deprecated) { delete base[key] } } - return base + return base as T } // end the repetition and the job itself diff --git a/packages/types/src/api/web/app/automation.ts b/packages/types/src/api/web/app/automation.ts new file mode 100644 index 00000000000..c10f19c88d0 --- /dev/null +++ b/packages/types/src/api/web/app/automation.ts @@ -0,0 +1,21 @@ +import { + AutomationActionStepId, + AutomationStepDefinition, + AutomationTriggerDefinition, + AutomationTriggerStepId, +} from "../../../documents" + +export type GetAutomationTriggerDefinitionsResponse = Record< + keyof typeof AutomationTriggerStepId, + AutomationTriggerDefinition +> + +export type GetAutomationActionDefinitionsResponse = Record< + keyof typeof AutomationActionStepId, + AutomationStepDefinition +> + +export interface GetAutomationStepDefinitionsResponse { + trigger: GetAutomationTriggerDefinitionsResponse + action: GetAutomationActionDefinitionsResponse +} diff --git a/packages/types/src/api/web/app/index.ts b/packages/types/src/api/web/app/index.ts index 55e1428fb91..3b7b183cc39 100644 --- a/packages/types/src/api/web/app/index.ts +++ b/packages/types/src/api/web/app/index.ts @@ -8,3 +8,4 @@ export * from "./permission" export * from "./attachment" export * from "./user" export * from "./rowAction" +export * from "./automation" diff --git a/packages/types/src/api/web/automation.ts b/packages/types/src/api/web/automation.ts index 06080fc6678..0f0699939e1 100644 --- a/packages/types/src/api/web/automation.ts +++ b/packages/types/src/api/web/automation.ts @@ -1,8 +1,58 @@ import { DocumentDestroyResponse } from "@budibase/nano" -import { Automation } from "../../documents" +import { + Automation, + AutomationLogPage, + AutomationStatus, + Row, +} from "../../documents" export interface DeleteAutomationResponse extends DocumentDestroyResponse {} export interface FetchAutomationResponse { automations: Automation[] } + +export interface FindAutomationResponse extends Automation {} + +export interface UpdateAutomationRequest extends Automation {} +export interface UpdateAutomationResponse { + message: string + automation: Automation +} + +export interface CreateAutomationRequest extends Automation {} +export interface CreateAutomationResponse { + message: string + automation: Automation +} + +export interface SearchAutomationLogsRequest { + startDate?: string + status?: AutomationStatus + automationId?: string + page?: string +} +export interface SearchAutomationLogsResponse extends AutomationLogPage {} + +export interface ClearAutomationLogRequest { + automationId: string + appId: string +} +export interface ClearAutomationLogResponse { + message: string +} + +export interface TriggerAutomationRequest { + fields: Record + // time in seconds + timeout: number +} +export type TriggerAutomationResponse = Record | undefined + +export interface TestAutomationRequest { + id?: string + revision?: string + fields: Record + row?: Row +} +export interface TestAutomationResponse {} diff --git a/packages/types/src/documents/app/automation/schema.ts b/packages/types/src/documents/app/automation/schema.ts index b8a19b7b450..efdf60a4e25 100644 --- a/packages/types/src/documents/app/automation/schema.ts +++ b/packages/types/src/documents/app/automation/schema.ts @@ -311,6 +311,7 @@ export type AutomationStep = type EmptyInputs = {} export type AutomationStepDefinition = Omit & { inputs: EmptyInputs + deprecated?: boolean } export type AutomationTriggerDefinition = Omit< @@ -318,6 +319,7 @@ export type AutomationTriggerDefinition = Omit< "id" | "inputs" > & { inputs: EmptyInputs + deprecated?: boolean } export type AutomationTriggerInputs = From d83bd47bd78b348044bba5b177b270f1c4c3015a Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Nov 2024 17:13:39 +0000 Subject: [PATCH 04/13] Fixing some automation typing issues. --- .../server/src/api/controllers/automation.ts | 6 +++++- packages/server/src/automations/triggers.ts | 11 ++++++++++- packages/server/src/definitions/automations.ts | 3 +++ packages/server/src/threads/automation.ts | 18 ++++++++++++------ 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index 89f664853a5..d13b0d3191a 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -177,7 +177,7 @@ export async function trigger( let hasCollectStep = sdk.automations.utils.checkForCollectStep(automation) if (hasCollectStep && (await features.isSyncAutomationsEnabled())) { try { - const response: AutomationResults = await triggers.externalTrigger( + const response = await triggers.externalTrigger( automation, { fields: ctx.request.body.fields, @@ -188,6 +188,10 @@ export async function trigger( { getResponses: true } ) + if (!("steps" in response)) { + ctx.throw(400, "Unable to collect response") + } + let collectedValue = response.steps.find( step => step.stepId === AutomationActionStepId.COLLECT ) diff --git a/packages/server/src/automations/triggers.ts b/packages/server/src/automations/triggers.ts index f422c14acb4..3a1e4785227 100644 --- a/packages/server/src/automations/triggers.ts +++ b/packages/server/src/automations/triggers.ts @@ -20,6 +20,7 @@ import { AutomationStatus, AutomationRowEvent, UserBindings, + AutomationResults, } from "@budibase/types" import { executeInThread } from "../threads/automation" import { dataFilters, sdk } from "@budibase/shared-core" @@ -32,6 +33,14 @@ const JOB_OPTS = { import * as automationUtils from "../automations/automationUtils" import { doesTableExist } from "../sdk/app/tables/getters" +type DidNotTriggerResponse = { + outputs: { + success: false + status: AutomationStatus.STOPPED + } + message: AutomationStoppedReason.TRIGGER_FILTER_NOT_MET +} + async function getAllAutomations() { const db = context.getAppDB() let automations = await db.allDocs( @@ -148,7 +157,7 @@ export async function externalTrigger( user?: UserBindings }, { getResponses }: { getResponses?: boolean } = {} -): Promise> { +): Promise { if (automation.disabled) { throw new Error("Automation is disabled") } diff --git a/packages/server/src/definitions/automations.ts b/packages/server/src/definitions/automations.ts index e45c5552017..67d6e04e9df 100644 --- a/packages/server/src/definitions/automations.ts +++ b/packages/server/src/definitions/automations.ts @@ -26,3 +26,6 @@ export interface AutomationContext extends AutomationResults { company?: string } } + +export interface AutomationResponse + extends Omit {} diff --git a/packages/server/src/threads/automation.ts b/packages/server/src/threads/automation.ts index 7e8f9475804..2d10f5d1fb8 100644 --- a/packages/server/src/threads/automation.ts +++ b/packages/server/src/threads/automation.ts @@ -30,7 +30,11 @@ import { UserBindings, isBasicSearchOperator, } from "@budibase/types" -import { AutomationContext, TriggerOutput } from "../definitions/automations" +import { + AutomationContext, + AutomationResponse, + TriggerOutput, +} from "../definitions/automations" import { WorkerCallback } from "./definitions" import { context, logging, configs } from "@budibase/backend-core" import { @@ -81,7 +85,7 @@ class Orchestrator { private job: Job private loopStepOutputs: LoopStep[] private stopped: boolean - private executionOutput: Omit + private executionOutput: AutomationResponse private currentUser: UserBindings | undefined constructor(job: AutomationJob) { @@ -257,7 +261,7 @@ class Orchestrator { }) } - async execute(): Promise { + async execute(): Promise { return tracer.trace( "Orchestrator.execute", { resource: "automation" }, @@ -723,7 +727,9 @@ export function execute(job: Job, callback: WorkerCallback) { }) } -export async function executeInThread(job: Job) { +export async function executeInThread( + job: Job +): Promise { const appId = job.data.event.appId if (!appId) { throw new Error("Unable to execute, event doesn't contain app ID.") @@ -735,7 +741,7 @@ export async function executeInThread(job: Job) { }, job.data.event.timeout || env.AUTOMATION_THREAD_TIMEOUT) }) - return await context.doInAppContext(appId, async () => { + return (await context.doInAppContext(appId, async () => { await context.ensureSnippetContext() const envVars = await sdkUtils.getEnvironmentVariables() // put into automation thread for whole context @@ -746,7 +752,7 @@ export async function executeInThread(job: Job) { timeoutPromise, ]) }) - }) + })) as AutomationResponse } export const removeStalled = async (job: Job) => { From 1094b880426c0ae3dbb269ff9de359e2847b23ab Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Nov 2024 17:25:08 +0000 Subject: [PATCH 05/13] Backup, component and datasource API typing. --- packages/server/src/api/controllers/backup.ts | 16 +++++++++------- packages/server/src/api/controllers/component.ts | 11 +++++++++-- .../server/src/api/controllers/datasource.ts | 14 ++++++++++---- packages/types/src/api/web/app/component.ts | 4 ++++ packages/types/src/api/web/app/datasource.ts | 11 +++++++++++ packages/types/src/api/web/app/index.ts | 1 + packages/types/src/api/web/application.ts | 8 ++++++++ 7 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 packages/types/src/api/web/app/component.ts diff --git a/packages/server/src/api/controllers/backup.ts b/packages/server/src/api/controllers/backup.ts index 8e1881a5fc2..21041961393 100644 --- a/packages/server/src/api/controllers/backup.ts +++ b/packages/server/src/api/controllers/backup.ts @@ -1,14 +1,16 @@ import sdk from "../../sdk" import { events, context, db } from "@budibase/backend-core" import { DocumentType } from "../../db/utils" -import { App, Ctx } from "@budibase/types" +import { + App, + Ctx, + ExportAppDumpRequest, + ExportAppDumpResponse, +} from "@budibase/types" -interface ExportAppDumpRequest { - excludeRows: boolean - encryptPassword?: string -} - -export async function exportAppDump(ctx: Ctx) { +export async function exportAppDump( + ctx: Ctx +) { const { appId } = ctx.query as any const { excludeRows, encryptPassword } = ctx.request.body diff --git a/packages/server/src/api/controllers/component.ts b/packages/server/src/api/controllers/component.ts index 6d4d3e2d214..c6d8551adcd 100644 --- a/packages/server/src/api/controllers/component.ts +++ b/packages/server/src/api/controllers/component.ts @@ -1,9 +1,16 @@ import { DocumentType } from "../../db/utils" -import { App, Plugin, UserCtx } from "@budibase/types" +import { + App, + FetchComponentDefinitionResponse, + Plugin, + UserCtx, +} from "@budibase/types" import { db as dbCore, context, tenancy } from "@budibase/backend-core" import { getComponentLibraryManifest } from "../../utilities/fileSystem" -export async function fetchAppComponentDefinitions(ctx: UserCtx) { +export async function fetchAppComponentDefinitions( + ctx: UserCtx +) { try { const db = context.getAppDB() const app = await db.get(DocumentType.APP_METADATA) diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index 97cf8db2996..3b635a6038a 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -23,13 +23,17 @@ import { Table, RowValue, DynamicVariable, + FetchDatasourcesResponse, + FindDatasourcesResponse, + DestroyDatasourceResponse, + FetchExternalSchemaResponse, } from "@budibase/types" import sdk from "../../sdk" import { builderSocket } from "../../websockets" import { isEqual } from "lodash" import { processTable } from "../../sdk/app/tables/getters" -export async function fetch(ctx: UserCtx) { +export async function fetch(ctx: UserCtx) { ctx.body = await sdk.datasources.fetch() } @@ -260,7 +264,7 @@ async function destroyInternalTablesBySourceId(datasourceId: string) { } } -export async function destroy(ctx: UserCtx) { +export async function destroy(ctx: UserCtx) { const db = context.getAppDB() const datasourceId = ctx.params.datasourceId @@ -291,12 +295,14 @@ export async function destroy(ctx: UserCtx) { builderSocket?.emitDatasourceDeletion(ctx, datasourceId) } -export async function find(ctx: UserCtx) { +export async function find(ctx: UserCtx) { const datasource = await sdk.datasources.get(ctx.params.datasourceId) ctx.body = await sdk.datasources.removeSecretSingle(datasource) } -export async function getExternalSchema(ctx: UserCtx) { +export async function getExternalSchema( + ctx: UserCtx +) { const datasource = await sdk.datasources.get(ctx.params.datasourceId) const enrichedDatasource = await sdk.datasources.getAndMergeDatasource( datasource diff --git a/packages/types/src/api/web/app/component.ts b/packages/types/src/api/web/app/component.ts new file mode 100644 index 00000000000..486809a6b1e --- /dev/null +++ b/packages/types/src/api/web/app/component.ts @@ -0,0 +1,4 @@ +export type FetchComponentDefinitionResponse = Record< + string, + Record +> diff --git a/packages/types/src/api/web/app/datasource.ts b/packages/types/src/api/web/app/datasource.ts index f9316659172..feb930b1841 100644 --- a/packages/types/src/api/web/app/datasource.ts +++ b/packages/types/src/api/web/app/datasource.ts @@ -42,3 +42,14 @@ export interface BuildSchemaFromSourceResponse { datasource: Datasource errors: Record } + +export type FetchDatasourcesResponse = Datasource[] +export type FindDatasourcesResponse = Datasource + +export interface DestroyDatasourceResponse { + message: string +} + +export interface FetchExternalSchemaResponse { + schema: string +} diff --git a/packages/types/src/api/web/app/index.ts b/packages/types/src/api/web/app/index.ts index 3b7b183cc39..9cc0bf36b6a 100644 --- a/packages/types/src/api/web/app/index.ts +++ b/packages/types/src/api/web/app/index.ts @@ -9,3 +9,4 @@ export * from "./attachment" export * from "./user" export * from "./rowAction" export * from "./automation" +export * from "./component" diff --git a/packages/types/src/api/web/application.ts b/packages/types/src/api/web/application.ts index 168f18ede34..acbfedf5e0e 100644 --- a/packages/types/src/api/web/application.ts +++ b/packages/types/src/api/web/application.ts @@ -1,5 +1,6 @@ import type { PlanType } from "../../sdk" import type { Layout, App, Screen } from "../../documents" +import { ReadStream } from "fs" export interface SyncAppResponse { message: string @@ -70,3 +71,10 @@ export interface ImportToUpdateAppResponse { export interface SetRevertableAppVersionRequest { revertableVersion: string } + +export interface ExportAppDumpRequest { + excludeRows: boolean + encryptPassword?: string +} + +export type ExportAppDumpResponse = ReadStream From fd71afde1dd46dd7e43c2b84fbe6e18e46361e87 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Nov 2024 17:59:08 +0000 Subject: [PATCH 06/13] Deployment API typing. --- .../src/api/controllers/deploy/Deployment.ts | 5 ++-- .../src/api/controllers/deploy/index.ts | 29 ++++++++++++------- packages/types/src/api/web/deployment.ts | 13 ++++++++- .../types/src/documents/app/deployment.ts | 17 ++++++++++- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/packages/server/src/api/controllers/deploy/Deployment.ts b/packages/server/src/api/controllers/deploy/Deployment.ts index fe817730b60..9d5e5431870 100644 --- a/packages/server/src/api/controllers/deploy/Deployment.ts +++ b/packages/server/src/api/controllers/deploy/Deployment.ts @@ -1,4 +1,5 @@ import { context, utils } from "@budibase/backend-core" +import { DeploymentStatus } from "@budibase/types" /** * This is used to pass around information about the deployment that is occurring @@ -6,7 +7,7 @@ import { context, utils } from "@budibase/backend-core" export default class Deployment { _id: string verification: any - status?: string + status?: DeploymentStatus err?: any appUrl?: string @@ -25,7 +26,7 @@ export default class Deployment { return this.verification } - setStatus(status: string, err?: any) { + setStatus(status: DeploymentStatus, err?: any) { this.status = status if (err) { this.err = err diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index 6a56f7d4687..652086f5715 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -10,22 +10,23 @@ import { backups } from "@budibase/pro" import { App, AppBackupTrigger, + DeploymentDoc, + FetchDeploymentResponse, PublishAppResponse, UserCtx, + DeploymentStatus, + DeploymentProgressResponse, } from "@budibase/types" import sdk from "../../../sdk" import { builderSocket } from "../../../websockets" // the max time we can wait for an invalidation to complete before considering it failed const MAX_PENDING_TIME_MS = 30 * 60000 -const DeploymentStatus = { - SUCCESS: "SUCCESS", - PENDING: "PENDING", - FAILURE: "FAILURE", -} // checks that deployments are in a good state, any pending will be updated -async function checkAllDeployments(deployments: any) { +async function checkAllDeployments( + deployments: any +): Promise<{ updated: boolean; deployments: DeploymentDoc }> { let updated = false let deployment: any for (deployment of Object.values(deployments.history)) { @@ -101,7 +102,9 @@ async function initDeployedApp(prodAppId: any) { }) } -export async function fetchDeployments(ctx: any) { +export async function fetchDeployments( + ctx: UserCtx +) { try { const db = context.getAppDB() const deploymentDoc = await db.get(DocumentType.DEPLOYMENTS) @@ -109,17 +112,21 @@ export async function fetchDeployments(ctx: any) { if (updated) { await db.put(deployments) } - ctx.body = Object.values(deployments.history).reverse() + ctx.body = deployments.history + ? Object.values(deployments.history).reverse() + : [] } catch (err) { ctx.body = [] } } -export async function deploymentProgress(ctx: any) { +export async function deploymentProgress( + ctx: UserCtx +) { try { const db = context.getAppDB() - const deploymentDoc = await db.get(DocumentType.DEPLOYMENTS) - ctx.body = deploymentDoc[ctx.params.deploymentId] + const deploymentDoc = await db.get(DocumentType.DEPLOYMENTS) + ctx.body = deploymentDoc.history?.[ctx.params.deploymentId] } catch (err) { ctx.throw( 500, diff --git a/packages/types/src/api/web/deployment.ts b/packages/types/src/api/web/deployment.ts index a9a007ed8f1..9e4caccc242 100644 --- a/packages/types/src/api/web/deployment.ts +++ b/packages/types/src/api/web/deployment.ts @@ -1,3 +1,14 @@ -import { DeploymentDoc } from "../../documents" +import { DeploymentDoc, DeploymentStatus } from "../../documents" export interface PublishAppResponse extends DeploymentDoc {} + +export type DeploymentProgressResponse = + | { + _id: string + appId: string + status?: DeploymentStatus + updatedAt: number + } + | undefined + +export type FetchDeploymentResponse = DeploymentProgressResponse[] diff --git a/packages/types/src/documents/app/deployment.ts b/packages/types/src/documents/app/deployment.ts index 63d3aea5f33..3216ebae3d6 100644 --- a/packages/types/src/documents/app/deployment.ts +++ b/packages/types/src/documents/app/deployment.ts @@ -1,7 +1,22 @@ +export enum DeploymentStatus { + SUCCESS = "SUCCESS", + PENDING = "PENDING", + FAILURE = "FAILURE", +} + export interface DeploymentDoc { _id: string verification: any - status?: string + status?: DeploymentStatus + history?: Record< + string, + { + _id: string + appId: string + status?: DeploymentStatus + updatedAt: number + } + > err?: any appUrl?: string } From b1cd134ee04104b436080232ea963b2646c6bda1 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 2 Dec 2024 14:42:46 +0000 Subject: [PATCH 07/13] Dev api. --- packages/server/src/api/controllers/application.ts | 1 - packages/server/src/api/controllers/dev.ts | 4 ++-- packages/types/src/api/web/dev.ts | 3 +++ packages/types/src/api/web/index.ts | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 packages/types/src/api/web/dev.ts diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 9170ba54c6d..3925df8ab02 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -68,7 +68,6 @@ import { ImportToUpdateAppRequest, ImportToUpdateAppResponse, SetRevertableAppVersionRequest, - SetRevertableAppVersionResponse, } from "@budibase/types" import { BASE_LAYOUT_PROP_IDS } from "../../constants/layouts" import sdk from "../../sdk" diff --git a/packages/server/src/api/controllers/dev.ts b/packages/server/src/api/controllers/dev.ts index 497da088c6b..41e4a3a20a0 100644 --- a/packages/server/src/api/controllers/dev.ts +++ b/packages/server/src/api/controllers/dev.ts @@ -11,7 +11,7 @@ import { db as dbCore, cache, } from "@budibase/backend-core" -import { App } from "@budibase/types" +import { App, Ctx, GetVersionResponse } from "@budibase/types" async function redirect( ctx: any, @@ -131,7 +131,7 @@ export async function revert(ctx: any) { } } -export async function getBudibaseVersion(ctx: any) { +export async function getBudibaseVersion(ctx: Ctx) { const version = envCore.VERSION ctx.body = { version, diff --git a/packages/types/src/api/web/dev.ts b/packages/types/src/api/web/dev.ts new file mode 100644 index 00000000000..f3195f58d3a --- /dev/null +++ b/packages/types/src/api/web/dev.ts @@ -0,0 +1,3 @@ +export interface GetVersionResponse { + version: string +} diff --git a/packages/types/src/api/web/index.ts b/packages/types/src/api/web/index.ts index 4c62d97dafe..4021eafee83 100644 --- a/packages/types/src/api/web/index.ts +++ b/packages/types/src/api/web/index.ts @@ -18,3 +18,4 @@ export * from "./role" export * from "./plugins" export * from "./apikeys" export * from "./deployment" +export * from "./dev" From bc3658e2cb7452a4dd78c7b6d01dac172436af2d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 2 Dec 2024 15:12:27 +0000 Subject: [PATCH 08/13] Adding fix for build issue. --- packages/server/src/api/controllers/automation.ts | 1 - packages/server/src/automations/tests/loop.spec.ts | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/controllers/automation.ts b/packages/server/src/api/controllers/automation.ts index d13b0d3191a..c843dca89b1 100644 --- a/packages/server/src/api/controllers/automation.ts +++ b/packages/server/src/api/controllers/automation.ts @@ -9,7 +9,6 @@ import { App, Automation, AutomationActionStepId, - AutomationResults, UserCtx, DeleteAutomationResponse, FetchAutomationResponse, diff --git a/packages/server/src/automations/tests/loop.spec.ts b/packages/server/src/automations/tests/loop.spec.ts index 372c3855b3b..2199a2a3a0d 100644 --- a/packages/server/src/automations/tests/loop.spec.ts +++ b/packages/server/src/automations/tests/loop.spec.ts @@ -3,7 +3,7 @@ import * as triggers from "../triggers" import { loopAutomation } from "../../tests/utilities/structures" import { context } from "@budibase/backend-core" import * as setup from "./utilities" -import { Table, LoopStepType } from "@budibase/types" +import { Table, LoopStepType, AutomationResults } from "@budibase/types" import * as loopUtils from "../loopUtils" import { LoopInput } from "../../definitions/automations" @@ -20,15 +20,19 @@ describe("Attempt to run a basic loop automation", () => { afterAll(setup.afterAll) - async function runLoop(loopOpts?: LoopInput) { + async function runLoop(loopOpts?: LoopInput): Promise { const appId = config.getAppId() return await context.doInAppContext(appId, async () => { const params = { fields: { appId } } - return await triggers.externalTrigger( + const result = await triggers.externalTrigger( loopAutomation(table._id!, loopOpts), params, { getResponses: true } ) + if ("outputs" in result && !result.outputs.success) { + throw new Error("Unable to proceed - failed to return anything.") + } + return result as AutomationResults }) } From fe9e4d1c5a8768341f1d23a763adeece3b850b1e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 2 Dec 2024 15:26:12 +0000 Subject: [PATCH 09/13] More typing fixes. --- packages/server/src/api/controllers/webhook.ts | 15 ++++++++++----- .../src/automations/steps/triggerAutomationRun.ts | 13 ++++++++----- packages/server/src/automations/triggers.ts | 8 ++++++++ .../src/tests/utilities/TestConfiguration.ts | 2 +- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/webhook.ts b/packages/server/src/api/controllers/webhook.ts index d667134f4dd..0f8f7be0ef5 100644 --- a/packages/server/src/api/controllers/webhook.ts +++ b/packages/server/src/api/controllers/webhook.ts @@ -10,6 +10,7 @@ import { } from "@budibase/types" import sdk from "../../sdk" import * as pro from "@budibase/pro" +import { isAutomationResults } from "../../automations/triggers" const toJsonSchema = require("to-json-schema") const validate = require("jsonschema").validate @@ -94,12 +95,16 @@ export async function trigger(ctx: BBContext) { { getResponses: true } ) - let collectedValue = response.steps.find( - (step: any) => step.stepId === AutomationActionStepId.COLLECT - ) + if (triggers.isAutomationResults(response)) { + let collectedValue = response.steps.find( + (step: any) => step.stepId === AutomationActionStepId.COLLECT + ) - ctx.status = 200 - ctx.body = collectedValue.outputs + ctx.status = 200 + ctx.body = collectedValue?.outputs + } else { + ctx.throw(400, "Automation did not have a collect block.") + } } else { await triggers.externalTrigger(target, { body: ctx.request.body, diff --git a/packages/server/src/automations/steps/triggerAutomationRun.ts b/packages/server/src/automations/steps/triggerAutomationRun.ts index c43f46b6f92..f1cf65b182e 100644 --- a/packages/server/src/automations/steps/triggerAutomationRun.ts +++ b/packages/server/src/automations/steps/triggerAutomationRun.ts @@ -3,7 +3,6 @@ import { AutomationStepDefinition, AutomationStepType, AutomationIOType, - AutomationResults, Automation, AutomationCustomIOType, TriggerAutomationStepInputs, @@ -78,7 +77,7 @@ export async function run({ const db = context.getAppDB() let automation = await db.get(inputs.automation.automationId) - const response: AutomationResults = await triggers.externalTrigger( + const response = await triggers.externalTrigger( automation, { fields: { ...fieldParams }, @@ -88,9 +87,13 @@ export async function run({ { getResponses: true } ) - return { - success: true, - value: response.steps, + if (triggers.isAutomationResults(response)) { + return { + success: true, + value: response.steps, + } + } else { + throw new Error("Automation did not have a collect block") } } } else { diff --git a/packages/server/src/automations/triggers.ts b/packages/server/src/automations/triggers.ts index 3a1e4785227..ed0aaaf3ec4 100644 --- a/packages/server/src/automations/triggers.ts +++ b/packages/server/src/automations/triggers.ts @@ -148,6 +148,14 @@ function rowPassesFilters(row: Row, filters: SearchFilters) { return filteredRows.length > 0 } +export function isAutomationResults( + response: AutomationResults | DidNotTriggerResponse | AutomationJob +): response is AutomationResults { + return ( + response !== null && "steps" in response && Array.isArray(response.steps) + ) +} + export async function externalTrigger( automation: Automation, params: { diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index abecf6df444..2d36e7855b0 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -621,7 +621,7 @@ export default class TestConfiguration { } async unpublish() { - const response = await this._req(appController.unpublish, { + const response = await this._req(appController.unpublish, undefined, { appId: this.appId, }) this.prodAppId = undefined From 24be6ef496376a88532e9d92c4fd20d320f60f6d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 2 Dec 2024 15:32:59 +0000 Subject: [PATCH 10/13] Linting. --- packages/server/src/api/controllers/webhook.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server/src/api/controllers/webhook.ts b/packages/server/src/api/controllers/webhook.ts index 0f8f7be0ef5..7c648ea827d 100644 --- a/packages/server/src/api/controllers/webhook.ts +++ b/packages/server/src/api/controllers/webhook.ts @@ -10,7 +10,6 @@ import { } from "@budibase/types" import sdk from "../../sdk" import * as pro from "@budibase/pro" -import { isAutomationResults } from "../../automations/triggers" const toJsonSchema = require("to-json-schema") const validate = require("jsonschema").validate From 98de7e69d1e5dd8d367191dec4117b46697fd1e6 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 2 Dec 2024 16:40:50 +0000 Subject: [PATCH 11/13] Last parts of dev API. --- packages/server/src/api/controllers/dev.ts | 12 +++++++++--- packages/types/src/api/web/dev.ts | 8 ++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/dev.ts b/packages/server/src/api/controllers/dev.ts index 41e4a3a20a0..ad0909a2942 100644 --- a/packages/server/src/api/controllers/dev.ts +++ b/packages/server/src/api/controllers/dev.ts @@ -11,7 +11,13 @@ import { db as dbCore, cache, } from "@budibase/backend-core" -import { App, Ctx, GetVersionResponse } from "@budibase/types" +import { + App, + ClearDevLockResponse, + Ctx, + GetVersionResponse, + RevertAppResponse, +} from "@budibase/types" async function redirect( ctx: any, @@ -69,7 +75,7 @@ export function buildRedirectDelete(path: string) { } } -export async function clearLock(ctx: any) { +export async function clearLock(ctx: Ctx) { const { appId } = ctx.params try { await redisClearLock(appId, ctx.user) @@ -81,7 +87,7 @@ export async function clearLock(ctx: any) { } } -export async function revert(ctx: any) { +export async function revert(ctx: Ctx) { const { appId } = ctx.params const productionAppId = dbCore.getProdAppID(appId) diff --git a/packages/types/src/api/web/dev.ts b/packages/types/src/api/web/dev.ts index f3195f58d3a..461676a4804 100644 --- a/packages/types/src/api/web/dev.ts +++ b/packages/types/src/api/web/dev.ts @@ -1,3 +1,11 @@ export interface GetVersionResponse { version: string } + +export interface ClearDevLockResponse { + message: string +} + +export interface RevertAppResponse { + message: string +} From d42c4118fe0c96a0bd6cf47ebed755938a8bca17 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 2 Dec 2024 16:58:35 +0000 Subject: [PATCH 12/13] Cleanup. --- packages/server/src/api/controllers/apikeys.ts | 6 +++--- packages/server/src/api/controllers/application.ts | 4 ++-- packages/server/src/api/controllers/datasource.ts | 4 ++-- packages/types/src/api/web/apikeys.ts | 4 ++-- packages/types/src/api/web/app/datasource.ts | 2 +- packages/types/src/api/web/application.ts | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/apikeys.ts b/packages/server/src/api/controllers/apikeys.ts index 8f841cd4573..95253b09c51 100644 --- a/packages/server/src/api/controllers/apikeys.ts +++ b/packages/server/src/api/controllers/apikeys.ts @@ -4,8 +4,8 @@ import { UserCtx, ApiKeyDoc, ApiKeyFetchResponse, - ApiKeyUpdateRequest, - ApiKeyUpdateResponse, + UpdateApiKeyRequest, + UpdateApiKeyResponse, } from "@budibase/types" const KEYS_DOC = dbCore.StaticDatabases.GLOBAL.docs.apiKeys @@ -40,7 +40,7 @@ export async function fetch(ctx: UserCtx) { } export async function update( - ctx: UserCtx + ctx: UserCtx ) { const key = ctx.params.key const value = ctx.request.body.value diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 3925df8ab02..d032f14150a 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -64,7 +64,7 @@ import { FetchAppsResponse, UpdateAppClientResponse, RevertAppClientResponse, - DestroyAppResponse, + DeleteAppResponse, ImportToUpdateAppRequest, ImportToUpdateAppResponse, SetRevertableAppVersionRequest, @@ -685,7 +685,7 @@ async function postDestroyApp(ctx: UserCtx) { } } -export async function destroy(ctx: UserCtx) { +export async function destroy(ctx: UserCtx) { await preDestroyApp(ctx) const result = await destroyApp(ctx) await postDestroyApp(ctx) diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index 3b635a6038a..c4492f304cd 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -25,7 +25,7 @@ import { DynamicVariable, FetchDatasourcesResponse, FindDatasourcesResponse, - DestroyDatasourceResponse, + DeleteDatasourceResponse, FetchExternalSchemaResponse, } from "@budibase/types" import sdk from "../../sdk" @@ -264,7 +264,7 @@ async function destroyInternalTablesBySourceId(datasourceId: string) { } } -export async function destroy(ctx: UserCtx) { +export async function destroy(ctx: UserCtx) { const db = context.getAppDB() const datasourceId = ctx.params.datasourceId diff --git a/packages/types/src/api/web/apikeys.ts b/packages/types/src/api/web/apikeys.ts index e46d0d4db53..1d089cd0ac9 100644 --- a/packages/types/src/api/web/apikeys.ts +++ b/packages/types/src/api/web/apikeys.ts @@ -1,10 +1,10 @@ export type ApiKeyFetchResponse = Record -export interface ApiKeyUpdateRequest { +export interface UpdateApiKeyRequest { value: string } -export interface ApiKeyUpdateResponse { +export interface UpdateApiKeyResponse { _id: string _rev: string } diff --git a/packages/types/src/api/web/app/datasource.ts b/packages/types/src/api/web/app/datasource.ts index feb930b1841..6f982d7060e 100644 --- a/packages/types/src/api/web/app/datasource.ts +++ b/packages/types/src/api/web/app/datasource.ts @@ -46,7 +46,7 @@ export interface BuildSchemaFromSourceResponse { export type FetchDatasourcesResponse = Datasource[] export type FindDatasourcesResponse = Datasource -export interface DestroyDatasourceResponse { +export interface DeleteDatasourceResponse { message: string } diff --git a/packages/types/src/api/web/application.ts b/packages/types/src/api/web/application.ts index acbfedf5e0e..ed999ee574d 100644 --- a/packages/types/src/api/web/application.ts +++ b/packages/types/src/api/web/application.ts @@ -57,7 +57,7 @@ export interface UpdateAppResponse extends App {} export interface UpdateAppClientResponse extends App {} export interface RevertAppClientResponse extends App {} -export interface DestroyAppResponse { +export interface DeleteAppResponse { ok: boolean } From 1b15ef3b7e440fd474a6c8a9b1c4d0dc91b6bab0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 3 Dec 2024 11:43:28 +0000 Subject: [PATCH 13/13] PR comments. --- packages/server/src/api/controllers/auth.ts | 4 ++-- .../server/src/api/controllers/deploy/index.ts | 3 +++ packages/types/src/api/web/deployment.ts | 14 ++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/server/src/api/controllers/auth.ts b/packages/server/src/api/controllers/auth.ts index 6aab688c306..0742583a8d1 100644 --- a/packages/server/src/api/controllers/auth.ts +++ b/packages/server/src/api/controllers/auth.ts @@ -2,7 +2,7 @@ import { outputProcessing } from "../../utilities/rowProcessor" import { InternalTables } from "../../db/utils" import { getFullUser } from "../../utilities/users" import { roles, context, db as dbCore } from "@budibase/backend-core" -import { AppSelfResponse, ContextUser, Row, UserCtx } from "@budibase/types" +import { AppSelfResponse, ContextUser, UserCtx } from "@budibase/types" import sdk from "../../sdk" import { processUser } from "../../utilities/global" @@ -45,7 +45,7 @@ export async function fetchSelf(ctx: UserCtx) { try { const userTable = await sdk.tables.getTable(InternalTables.USER_METADATA) // specifically needs to make sure is enriched - ctx.body = (await outputProcessing(userTable, user as Row)) as ContextUser + ctx.body = await outputProcessing(userTable, user) } catch (err: any) { let response: ContextUser | {} // user didn't exist in app, don't pretend they do diff --git a/packages/server/src/api/controllers/deploy/index.ts b/packages/server/src/api/controllers/deploy/index.ts index 652086f5715..b05b82d79a8 100644 --- a/packages/server/src/api/controllers/deploy/index.ts +++ b/packages/server/src/api/controllers/deploy/index.ts @@ -126,6 +126,9 @@ export async function deploymentProgress( try { const db = context.getAppDB() const deploymentDoc = await db.get(DocumentType.DEPLOYMENTS) + if (!deploymentDoc.history?.[ctx.params.deploymentId]) { + ctx.throw(404, "No deployment found") + } ctx.body = deploymentDoc.history?.[ctx.params.deploymentId] } catch (err) { ctx.throw( diff --git a/packages/types/src/api/web/deployment.ts b/packages/types/src/api/web/deployment.ts index 9e4caccc242..f5ed9242b16 100644 --- a/packages/types/src/api/web/deployment.ts +++ b/packages/types/src/api/web/deployment.ts @@ -2,13 +2,11 @@ import { DeploymentDoc, DeploymentStatus } from "../../documents" export interface PublishAppResponse extends DeploymentDoc {} -export type DeploymentProgressResponse = - | { - _id: string - appId: string - status?: DeploymentStatus - updatedAt: number - } - | undefined +export interface DeploymentProgressResponse { + _id: string + appId: string + status?: DeploymentStatus + updatedAt: number +} export type FetchDeploymentResponse = DeploymentProgressResponse[]