Merge pull request #15120 from Budibase/chore/api-typing-3

Final app service API typing
This commit is contained in:
Michael Drury 2024-12-05 14:23:39 +00:00 committed by GitHub
commit 63a5821877
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 401 additions and 241 deletions

View File

@ -83,6 +83,7 @@
"@types/semver": "7.3.7", "@types/semver": "7.3.7",
"@types/tar-fs": "2.0.1", "@types/tar-fs": "2.0.1",
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@types/koa": "2.13.4",
"chance": "1.1.8", "chance": "1.1.8",
"ioredis-mock": "8.9.0", "ioredis-mock": "8.9.0",
"jest": "29.7.0", "jest": "29.7.0",

View File

@ -1,6 +1,10 @@
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
import type { Middleware, Next } from "koa"
export default async (ctx: BBContext | any, next: any) => { // this middleware exists purely to be overridden by middlewares supplied by the @budibase/pro library
const middleware = (async (ctx: Ctx, next: Next) => {
// Placeholder for audit log middleware // Placeholder for audit log middleware
return next() return next()
} }) as Middleware
export default middleware

View File

@ -22,6 +22,7 @@ import {
} from "@budibase/types" } from "@budibase/types"
import { ErrorCode, InvalidAPIKeyError } from "../errors" import { ErrorCode, InvalidAPIKeyError } from "../errors"
import tracer from "dd-trace" import tracer from "dd-trace"
import type { Middleware, Next } from "koa"
const ONE_MINUTE = env.SESSION_UPDATE_PERIOD const ONE_MINUTE = env.SESSION_UPDATE_PERIOD
? parseInt(env.SESSION_UPDATE_PERIOD) ? parseInt(env.SESSION_UPDATE_PERIOD)
@ -94,6 +95,14 @@ async function checkApiKey(
}) })
} }
function getHeader(ctx: Ctx, header: Header): string | undefined {
const contents = ctx.request.headers[header]
if (Array.isArray(contents)) {
throw new Error("Unexpected header format")
}
return contents
}
/** /**
* This middleware is tenancy aware, so that it does not depend on other middlewares being used. * This middleware is tenancy aware, so that it does not depend on other middlewares being used.
* The tenancy modules should not be used here and it should be assumed that the tenancy context * The tenancy modules should not be used here and it should be assumed that the tenancy context
@ -106,9 +115,9 @@ export default function (
} }
) { ) {
const noAuthOptions = noAuthPatterns ? buildMatcherRegex(noAuthPatterns) : [] const noAuthOptions = noAuthPatterns ? buildMatcherRegex(noAuthPatterns) : []
return async (ctx: Ctx | any, next: any) => { return (async (ctx: Ctx, next: Next) => {
let publicEndpoint = false let publicEndpoint = false
const version = ctx.request.headers[Header.API_VER] const version = getHeader(ctx, Header.API_VER)
// the path is not authenticated // the path is not authenticated
const found = matches(ctx, noAuthOptions) const found = matches(ctx, noAuthOptions)
if (found) { if (found) {
@ -116,18 +125,18 @@ export default function (
} }
try { try {
// check the actual user is authenticated first, try header or cookie // check the actual user is authenticated first, try header or cookie
let headerToken = ctx.request.headers[Header.TOKEN] let headerToken = getHeader(ctx, Header.TOKEN)
const authCookie = const authCookie =
getCookie<SessionCookie>(ctx, Cookie.Auth) || getCookie<SessionCookie>(ctx, Cookie.Auth) ||
openJwt<SessionCookie>(headerToken) openJwt<SessionCookie>(headerToken)
let apiKey = ctx.request.headers[Header.API_KEY] let apiKey = getHeader(ctx, Header.API_KEY)
if (!apiKey && ctx.request.headers[Header.AUTHORIZATION]) { if (!apiKey && ctx.request.headers[Header.AUTHORIZATION]) {
apiKey = ctx.request.headers[Header.AUTHORIZATION].split(" ")[1] apiKey = ctx.request.headers[Header.AUTHORIZATION].split(" ")[1]
} }
const tenantId = ctx.request.headers[Header.TENANT_ID] const tenantId = getHeader(ctx, Header.TENANT_ID)
let authenticated: boolean = false, let authenticated: boolean = false,
user: User | { tenantId: string } | undefined = undefined, user: User | { tenantId: string } | undefined = undefined,
internal: boolean = false, internal: boolean = false,
@ -243,5 +252,5 @@ export default function (
ctx.throw(err.status || 403, err) ctx.throw(err.status || 403, err)
} }
} }
} }) as Middleware
} }

View File

@ -1,6 +1,7 @@
import { Header } from "../constants" import { Header } from "../constants"
import { buildMatcherRegex, matches } from "./matchers" import { buildMatcherRegex, matches } from "./matchers"
import { BBContext, EndpointMatcher } from "@budibase/types" import { Ctx, EndpointMatcher } from "@budibase/types"
import type { Middleware, Next } from "koa"
/** /**
* GET, HEAD and OPTIONS methods are considered safe operations * GET, HEAD and OPTIONS methods are considered safe operations
@ -36,7 +37,7 @@ export default function (
opts: { noCsrfPatterns: EndpointMatcher[] } = { noCsrfPatterns: [] } opts: { noCsrfPatterns: EndpointMatcher[] } = { noCsrfPatterns: [] }
) { ) {
const noCsrfOptions = buildMatcherRegex(opts.noCsrfPatterns) const noCsrfOptions = buildMatcherRegex(opts.noCsrfPatterns)
return async (ctx: BBContext | any, next: any) => { return (async (ctx: Ctx, next: Next) => {
// don't apply for excluded paths // don't apply for excluded paths
const found = matches(ctx, noCsrfOptions) const found = matches(ctx, noCsrfOptions)
if (found) { if (found) {
@ -77,5 +78,5 @@ export default function (
} }
return next() return next()
} }) as Middleware
} }

View File

@ -1,11 +1,11 @@
import { Header } from "../constants" import { Header } from "../constants"
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
import { isValidInternalAPIKey } from "../utils" import { isValidInternalAPIKey } from "../utils"
/** /**
* API Key only endpoint. * API Key only endpoint.
*/ */
export default async (ctx: BBContext, next: any) => { export default async (ctx: Ctx, next: any) => {
const apiKey = ctx.request.headers[Header.API_KEY] const apiKey = ctx.request.headers[Header.API_KEY]
if (!apiKey) { if (!apiKey) {
ctx.throw(403, "Unauthorized") ctx.throw(403, "Unauthorized")

View File

@ -1,4 +1,4 @@
import { BBContext, EndpointMatcher, RegexMatcher } from "@budibase/types" import { Ctx, EndpointMatcher, RegexMatcher } from "@budibase/types"
const PARAM_REGEX = /\/:(.*?)(\/.*)?$/g const PARAM_REGEX = /\/:(.*?)(\/.*)?$/g
@ -27,7 +27,7 @@ export const buildMatcherRegex = (
}) })
} }
export const matches = (ctx: BBContext, options: RegexMatcher[]) => { export const matches = (ctx: Ctx, options: RegexMatcher[]) => {
return options.find(({ regex, method }) => { return options.find(({ regex, method }) => {
const urlMatch = regex.test(ctx.request.url) const urlMatch = regex.test(ctx.request.url)
const methodMatch = const methodMatch =

View File

@ -2,7 +2,7 @@ import { UserStatus } from "../../constants"
import { compare } from "../../utils" import { compare } from "../../utils"
import * as users from "../../users" import * as users from "../../users"
import { authError } from "./utils" import { authError } from "./utils"
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
const INVALID_ERR = "Invalid credentials" const INVALID_ERR = "Invalid credentials"
const EXPIRED = "This account has expired. Please reset your password" const EXPIRED = "This account has expired. Please reset your password"
@ -20,7 +20,7 @@ export const options = {
* @returns The authenticated user, or errors if they occur * @returns The authenticated user, or errors if they occur
*/ */
export async function authenticate( export async function authenticate(
ctx: BBContext, ctx: Ctx,
email: string, email: string,
password: string, password: string,
done: Function done: Function

View File

@ -3,11 +3,12 @@ import { getTenantIDFromCtx } from "../tenancy"
import { buildMatcherRegex, matches } from "./matchers" import { buildMatcherRegex, matches } from "./matchers"
import { Header } from "../constants" import { Header } from "../constants"
import { import {
BBContext, Ctx,
EndpointMatcher, EndpointMatcher,
GetTenantIdOptions, GetTenantIdOptions,
TenantResolutionStrategy, TenantResolutionStrategy,
} from "@budibase/types" } from "@budibase/types"
import type { Next, Middleware } from "koa"
export default function ( export default function (
allowQueryStringPatterns: EndpointMatcher[], allowQueryStringPatterns: EndpointMatcher[],
@ -17,7 +18,7 @@ export default function (
const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns) const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns)
const noTenancyOptions = buildMatcherRegex(noTenancyPatterns) const noTenancyOptions = buildMatcherRegex(noTenancyPatterns)
return async function (ctx: BBContext | any, next: any) { return async function (ctx: Ctx, next: Next) {
const allowNoTenant = const allowNoTenant =
opts.noTenancyRequired || !!matches(ctx, noTenancyOptions) opts.noTenancyRequired || !!matches(ctx, noTenancyOptions)
const tenantOpts: GetTenantIdOptions = { const tenantOpts: GetTenantIdOptions = {
@ -32,5 +33,5 @@ export default function (
const tenantId = getTenantIDFromCtx(ctx, tenantOpts) const tenantId = getTenantIDFromCtx(ctx, tenantOpts)
ctx.set(Header.TENANT_ID, tenantId as string) ctx.set(Header.TENANT_ID, tenantId as string)
return doInTenant(tenantId, next) return doInTenant(tenantId, next)
} } as Middleware
} }

View File

@ -592,7 +592,10 @@ export class AccessController {
) )
} }
async checkScreensAccess(screens: Screen[], userRoleId: string) { async checkScreensAccess(
screens: Screen[],
userRoleId: string
): Promise<Screen[]> {
let accessibleScreens = [] let accessibleScreens = []
// don't want to handle this with Promise.all as this would mean all custom roles would be // don't want to handle this with Promise.all as this would mean all custom roles would be
// retrieved at same time, it is likely a custom role will be re-used and therefore want // retrieved at same time, it is likely a custom role will be re-used and therefore want

View File

@ -6,7 +6,7 @@ import {
getPlatformURL, getPlatformURL,
} from "../context" } from "../context"
import { import {
BBContext, Ctx,
TenantResolutionStrategy, TenantResolutionStrategy,
GetTenantIdOptions, GetTenantIdOptions,
} from "@budibase/types" } from "@budibase/types"
@ -37,7 +37,7 @@ export const isUserInAppTenant = (appId: string, user?: any) => {
const ALL_STRATEGIES = Object.values(TenantResolutionStrategy) const ALL_STRATEGIES = Object.values(TenantResolutionStrategy)
export const getTenantIDFromCtx = ( export const getTenantIDFromCtx = (
ctx: BBContext, ctx: Ctx,
opts: GetTenantIdOptions opts: GetTenantIdOptions
): string | undefined => { ): string | undefined => {
// exit early if not multi-tenant // exit early if not multi-tenant

View File

@ -5,7 +5,7 @@ import * as db from "../../db"
import { Header } from "../../constants" import { Header } from "../../constants"
import { newid } from "../../utils" import { newid } from "../../utils"
import env from "../../environment" import env from "../../environment"
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
describe("utils", () => { describe("utils", () => {
const config = new DBTestConfiguration() const config = new DBTestConfiguration()
@ -109,7 +109,7 @@ describe("utils", () => {
}) })
describe("isServingBuilder", () => { describe("isServingBuilder", () => {
let ctx: BBContext let ctx: Ctx
const expectResult = (result: boolean) => const expectResult = (result: boolean) =>
expect(utils.isServingBuilder(ctx)).toBe(result) expect(utils.isServingBuilder(ctx)).toBe(result)
@ -133,7 +133,7 @@ describe("utils", () => {
}) })
describe("isServingBuilderPreview", () => { describe("isServingBuilderPreview", () => {
let ctx: BBContext let ctx: Ctx
const expectResult = (result: boolean) => const expectResult = (result: boolean) =>
expect(utils.isServingBuilderPreview(ctx)).toBe(result) expect(utils.isServingBuilderPreview(ctx)).toBe(result)
@ -157,7 +157,7 @@ describe("utils", () => {
}) })
describe("isPublicAPIRequest", () => { describe("isPublicAPIRequest", () => {
let ctx: BBContext let ctx: Ctx
const expectResult = (result: boolean) => const expectResult = (result: boolean) =>
expect(utils.isPublicApiRequest(ctx)).toBe(result) expect(utils.isPublicApiRequest(ctx)).toBe(result)

View File

@ -1,8 +1,8 @@
import { createMockContext, createMockCookies } from "@shopify/jest-koa-mocks" import { createMockContext, createMockCookies } from "@shopify/jest-koa-mocks"
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
export const newContext = (): BBContext => { export const newContext = (): Ctx => {
const ctx = createMockContext() as any const ctx = createMockContext() as Ctx
return { return {
...ctx, ...ctx,
path: "/", path: "/",

View File

@ -10,13 +10,16 @@ import { updateAppPackage } from "./application"
import { import {
Plugin, Plugin,
ScreenProps, ScreenProps,
BBContext,
Screen, Screen,
UserCtx, UserCtx,
FetchScreenResponse,
SaveScreenRequest,
SaveScreenResponse,
DeleteScreenResponse,
} from "@budibase/types" } from "@budibase/types"
import { builderSocket } from "../../websockets" import { builderSocket } from "../../websockets"
export async function fetch(ctx: BBContext) { export async function fetch(ctx: UserCtx<void, FetchScreenResponse>) {
const db = context.getAppDB() const db = context.getAppDB()
const screens = ( const screens = (
@ -37,7 +40,9 @@ export async function fetch(ctx: BBContext) {
) )
} }
export async function save(ctx: UserCtx<Screen, Screen>) { export async function save(
ctx: UserCtx<SaveScreenRequest, SaveScreenResponse>
) {
const db = context.getAppDB() const db = context.getAppDB()
let screen = ctx.request.body let screen = ctx.request.body
@ -107,7 +112,7 @@ export async function save(ctx: UserCtx<Screen, Screen>) {
builderSocket?.emitScreenUpdate(ctx, savedScreen) builderSocket?.emitScreenUpdate(ctx, savedScreen)
} }
export async function destroy(ctx: BBContext) { export async function destroy(ctx: UserCtx<void, DeleteScreenResponse>) {
const db = context.getAppDB() const db = context.getAppDB()
const id = ctx.params.screenId const id = ctx.params.screenId
const screen = await db.get<Screen>(id) const screen = await db.get<Screen>(id)

View File

@ -14,7 +14,3 @@ export async function execute(ctx: Ctx) {
throw err throw err
} }
} }
export async function save(ctx: Ctx) {
ctx.throw(501, "Not currently implemented")
}

View File

@ -27,7 +27,13 @@ import {
Ctx, Ctx,
DocumentType, DocumentType,
Feature, Feature,
GetSignedUploadUrlRequest,
GetSignedUploadUrlResponse,
ProcessAttachmentResponse, ProcessAttachmentResponse,
ServeAppResponse,
ServeBuilderPreviewResponse,
ServeClientLibraryResponse,
ToggleBetaFeatureResponse,
UserCtx, UserCtx,
} from "@budibase/types" } from "@budibase/types"
import { import {
@ -38,7 +44,9 @@ import {
import send from "koa-send" import send from "koa-send"
import { getThemeVariables } from "../../../constants/themes" import { getThemeVariables } from "../../../constants/themes"
export const toggleBetaUiFeature = async function (ctx: Ctx) { export const toggleBetaUiFeature = async function (
ctx: Ctx<void, ToggleBetaFeatureResponse>
) {
const cookieName = `beta:${ctx.params.feature}` const cookieName = `beta:${ctx.params.feature}`
if (ctx.cookies.get(cookieName)) { if (ctx.cookies.get(cookieName)) {
@ -66,13 +74,13 @@ export const toggleBetaUiFeature = async function (ctx: Ctx) {
} }
} }
export const serveBuilder = async function (ctx: Ctx) { export const serveBuilder = async function (ctx: Ctx<void, void>) {
const builderPath = join(TOP_LEVEL_PATH, "builder") const builderPath = join(TOP_LEVEL_PATH, "builder")
await send(ctx, ctx.file, { root: builderPath }) await send(ctx, ctx.file, { root: builderPath })
} }
export const uploadFile = async function ( export const uploadFile = async function (
ctx: Ctx<{}, ProcessAttachmentResponse> ctx: Ctx<void, ProcessAttachmentResponse>
) { ) {
const file = ctx.request?.files?.file const file = ctx.request?.files?.file
if (!file) { if (!file) {
@ -144,7 +152,7 @@ const requiresMigration = async (ctx: Ctx) => {
return latestMigrationApplied !== latestMigration return latestMigrationApplied !== latestMigration
} }
export const serveApp = async function (ctx: UserCtx) { export const serveApp = async function (ctx: UserCtx<void, ServeAppResponse>) {
if (ctx.url.includes("apple-touch-icon.png")) { if (ctx.url.includes("apple-touch-icon.png")) {
ctx.redirect("/builder/bblogo.png") ctx.redirect("/builder/bblogo.png")
return return
@ -249,7 +257,9 @@ export const serveApp = async function (ctx: UserCtx) {
} }
} }
export const serveBuilderPreview = async function (ctx: Ctx) { export const serveBuilderPreview = async function (
ctx: Ctx<void, ServeBuilderPreviewResponse>
) {
const db = context.getAppDB({ skip_setup: true }) const db = context.getAppDB({ skip_setup: true })
const appInfo = await db.get<App>(DocumentType.APP_METADATA) const appInfo = await db.get<App>(DocumentType.APP_METADATA)
@ -268,7 +278,9 @@ export const serveBuilderPreview = async function (ctx: Ctx) {
} }
} }
export const serveClientLibrary = async function (ctx: Ctx) { export const serveClientLibrary = async function (
ctx: Ctx<void, ServeClientLibraryResponse>
) {
const version = ctx.request.query.version const version = ctx.request.query.version
if (Array.isArray(version)) { if (Array.isArray(version)) {
@ -297,7 +309,9 @@ export const serveClientLibrary = async function (ctx: Ctx) {
} }
} }
export const getSignedUploadURL = async function (ctx: Ctx) { export const getSignedUploadURL = async function (
ctx: Ctx<GetSignedUploadUrlRequest, GetSignedUploadUrlResponse>
) {
// Ensure datasource is valid // Ensure datasource is valid
let datasource let datasource
try { try {

View File

@ -19,17 +19,18 @@ import {
EventType, EventType,
FetchTablesResponse, FetchTablesResponse,
FieldType, FieldType,
MigrateRequest, MigrateTableRequest,
MigrateResponse, MigrateTableResponse,
SaveTableRequest, SaveTableRequest,
SaveTableResponse, SaveTableResponse,
Table, Table,
TableResponse, FindTableResponse,
TableSourceType, TableSourceType,
UserCtx, UserCtx,
ValidateNewTableImportRequest, ValidateNewTableImportRequest,
ValidateTableImportRequest, ValidateTableImportRequest,
ValidateTableImportResponse, ValidateTableImportResponse,
DeleteTableResponse,
} from "@budibase/types" } from "@budibase/types"
import sdk from "../../../sdk" import sdk from "../../../sdk"
import { jsonFromCsvString } from "../../../utilities/csv" import { jsonFromCsvString } from "../../../utilities/csv"
@ -94,7 +95,7 @@ export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
ctx.body = result ctx.body = result
} }
export async function find(ctx: UserCtx<void, TableResponse>) { export async function find(ctx: UserCtx<void, FindTableResponse>) {
const tableId = ctx.params.tableId const tableId = ctx.params.tableId
const table = await sdk.tables.getTable(tableId) const table = await sdk.tables.getTable(tableId)
@ -137,7 +138,7 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
builderSocket?.emitTableUpdate(ctx, cloneDeep(savedTable)) builderSocket?.emitTableUpdate(ctx, cloneDeep(savedTable))
} }
export async function destroy(ctx: UserCtx) { export async function destroy(ctx: UserCtx<void, DeleteTableResponse>) {
const appId = ctx.appId const appId = ctx.appId
const tableId = ctx.params.tableId const tableId = ctx.params.tableId
await sdk.rowActions.deleteAll(tableId) await sdk.rowActions.deleteAll(tableId)
@ -223,7 +224,9 @@ export async function validateExistingTableImport(
} }
} }
export async function migrate(ctx: UserCtx<MigrateRequest, MigrateResponse>) { export async function migrate(
ctx: UserCtx<MigrateTableRequest, MigrateTableResponse>
) {
const { oldColumn, newColumn } = ctx.request.body const { oldColumn, newColumn } = ctx.request.body
let tableId = ctx.params.tableId as string let tableId = ctx.params.tableId as string
const table = await sdk.tables.getTable(tableId) const table = await sdk.tables.getTable(tableId)

View File

@ -1,13 +1,17 @@
import nodeFetch from "node-fetch" import nodeFetch from "node-fetch"
import { downloadTemplate as dlTemplate } from "../../utilities/fileSystem" import { downloadTemplate as dlTemplate } from "../../utilities/fileSystem"
import env from "../../environment" import env from "../../environment"
import { BBContext } from "@budibase/types" import {
DownloadTemplateResponse,
FetchTemplateResponse,
UserCtx,
} from "@budibase/types"
// development flag, can be used to test against templates exported locally // development flag, can be used to test against templates exported locally
const DEFAULT_TEMPLATES_BUCKET = const DEFAULT_TEMPLATES_BUCKET =
"prod-budi-templates.s3-eu-west-1.amazonaws.com" "prod-budi-templates.s3-eu-west-1.amazonaws.com"
export async function fetch(ctx: BBContext) { export async function fetch(ctx: UserCtx<void, FetchTemplateResponse>) {
let type = env.TEMPLATE_REPOSITORY let type = env.TEMPLATE_REPOSITORY
let response, let response,
error = false error = false
@ -32,7 +36,9 @@ export async function fetch(ctx: BBContext) {
// can't currently test this, have to ignore from coverage // can't currently test this, have to ignore from coverage
/* istanbul ignore next */ /* istanbul ignore next */
export async function downloadTemplate(ctx: BBContext) { export async function downloadTemplate(
ctx: UserCtx<void, DownloadTemplateResponse>
) {
const { type, name } = ctx.params const { type, name } = ctx.params
await dlTemplate(type, name) await dlTemplate(type, name)

View File

@ -7,19 +7,24 @@ import {
FetchUserMetadataResponse, FetchUserMetadataResponse,
FindUserMetadataResponse, FindUserMetadataResponse,
Flags, Flags,
SetFlagRequest, SetUserFlagRequest,
UpdateSelfMetadataRequest,
UpdateSelfMetadataResponse,
UpdateUserMetadataResponse,
UpdateUserMetadataRequest,
UserCtx, UserCtx,
UserMetadata, DeleteUserMetadataResponse,
SetUserFlagResponse,
GetUserFlagsResponse,
} from "@budibase/types" } from "@budibase/types"
import sdk from "../../sdk" import sdk from "../../sdk"
import { DocumentInsertResponse } from "@budibase/nano"
export async function fetchMetadata(ctx: Ctx<void, FetchUserMetadataResponse>) { export async function fetchMetadata(ctx: Ctx<void, FetchUserMetadataResponse>) {
ctx.body = await sdk.users.fetchMetadata() ctx.body = await sdk.users.fetchMetadata()
} }
export async function updateSelfMetadata( export async function updateSelfMetadata(
ctx: UserCtx<UserMetadata, DocumentInsertResponse> ctx: UserCtx<UpdateSelfMetadataRequest, UpdateSelfMetadataResponse>
) { ) {
// overwrite the ID with current users // overwrite the ID with current users
ctx.request.body._id = ctx.user?._id ctx.request.body._id = ctx.user?._id
@ -31,7 +36,7 @@ export async function updateSelfMetadata(
} }
export async function updateMetadata( export async function updateMetadata(
ctx: UserCtx<UserMetadata, DocumentInsertResponse> ctx: UserCtx<UpdateUserMetadataRequest, UpdateUserMetadataResponse>
) { ) {
const db = context.getAppDB() const db = context.getAppDB()
const user = ctx.request.body const user = ctx.request.body
@ -44,7 +49,9 @@ export async function updateMetadata(
ctx.body = await db.put(metadata) ctx.body = await db.put(metadata)
} }
export async function destroyMetadata(ctx: UserCtx<void, { message: string }>) { export async function destroyMetadata(
ctx: UserCtx<void, DeleteUserMetadataResponse>
) {
const db = context.getAppDB() const db = context.getAppDB()
try { try {
const dbUser = await sdk.users.get(ctx.params.id) const dbUser = await sdk.users.get(ctx.params.id)
@ -64,7 +71,7 @@ export async function findMetadata(
} }
export async function setFlag( export async function setFlag(
ctx: UserCtx<SetFlagRequest, { message: string }> ctx: UserCtx<SetUserFlagRequest, SetUserFlagResponse>
) { ) {
const userId = ctx.user?._id const userId = ctx.user?._id
const { flag, value } = ctx.request.body const { flag, value } = ctx.request.body
@ -84,7 +91,7 @@ export async function setFlag(
ctx.body = { message: "Flag set successfully" } ctx.body = { message: "Flag set successfully" }
} }
export async function getFlags(ctx: UserCtx<void, Flags>) { export async function getFlags(ctx: UserCtx<void, GetUserFlagsResponse>) {
const userId = ctx.user?._id const userId = ctx.user?._id
const docId = generateUserFlagID(userId!) const docId = generateUserFlagID(userId!)
const db = context.getAppDB() const db = context.getAppDB()

View File

@ -4,7 +4,6 @@ import {
Ctx, Ctx,
RequiredKeys, RequiredKeys,
UpdateViewRequest, UpdateViewRequest,
ViewResponse,
ViewResponseEnriched, ViewResponseEnriched,
ViewV2, ViewV2,
BasicViewFieldMetadata, BasicViewFieldMetadata,
@ -15,6 +14,8 @@ import {
ViewFetchResponseEnriched, ViewFetchResponseEnriched,
CountDistinctCalculationFieldMetadata, CountDistinctCalculationFieldMetadata,
CountCalculationFieldMetadata, CountCalculationFieldMetadata,
CreateViewResponse,
UpdateViewResponse,
} from "@budibase/types" } from "@budibase/types"
import { builderSocket, gridSocket } from "../../../websockets" import { builderSocket, gridSocket } from "../../../websockets"
import { helpers } from "@budibase/shared-core" import { helpers } from "@budibase/shared-core"
@ -132,7 +133,7 @@ export async function fetch(ctx: Ctx<void, ViewFetchResponseEnriched>) {
} }
} }
export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) { export async function create(ctx: Ctx<CreateViewRequest, CreateViewResponse>) {
const view = ctx.request.body const view = ctx.request.body
const { tableId } = view const { tableId } = view
@ -159,7 +160,7 @@ export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) {
gridSocket?.emitViewUpdate(ctx, result) gridSocket?.emitViewUpdate(ctx, result)
} }
export async function update(ctx: Ctx<UpdateViewRequest, ViewResponse>) { export async function update(ctx: Ctx<UpdateViewRequest, UpdateViewResponse>) {
const view = ctx.request.body const view = ctx.request.body
if (view.version !== 2) { if (view.version !== 2) {
@ -196,7 +197,7 @@ export async function update(ctx: Ctx<UpdateViewRequest, ViewResponse>) {
gridSocket?.emitViewUpdate(ctx, result) gridSocket?.emitViewUpdate(ctx, result)
} }
export async function remove(ctx: Ctx) { export async function remove(ctx: Ctx<void, void>) {
const { viewId } = ctx.params const { viewId } = ctx.params
const view = await sdk.views.remove(viewId) const view = await sdk.views.remove(viewId)

View File

@ -4,9 +4,17 @@ import { db as dbCore, context } from "@budibase/backend-core"
import { import {
Webhook, Webhook,
WebhookActionType, WebhookActionType,
BBContext, Ctx,
Automation, Automation,
AutomationActionStepId, AutomationActionStepId,
FetchWebhooksResponse,
SaveWebhookResponse,
SaveWebhookRequest,
DeleteWebhookResponse,
BuildWebhookSchemaRequest,
BuildWebhookSchemaResponse,
TriggerWebhookRequest,
TriggerWebhookResponse,
} from "@budibase/types" } from "@budibase/types"
import sdk from "../../sdk" import sdk from "../../sdk"
import * as pro from "@budibase/pro" import * as pro from "@budibase/pro"
@ -16,17 +24,17 @@ const validate = require("jsonschema").validate
const AUTOMATION_DESCRIPTION = "Generated from Webhook Schema" const AUTOMATION_DESCRIPTION = "Generated from Webhook Schema"
export async function fetch(ctx: BBContext) { export async function fetch(ctx: Ctx<void, FetchWebhooksResponse>) {
const db = context.getAppDB() const db = context.getAppDB()
const response = await db.allDocs( const response = await db.allDocs<Webhook>(
getWebhookParams(null, { getWebhookParams(null, {
include_docs: true, include_docs: true,
}) })
) )
ctx.body = response.rows.map((row: any) => row.doc) ctx.body = response.rows.filter(row => row.doc).map(row => row.doc!)
} }
export async function save(ctx: BBContext) { export async function save(ctx: Ctx<SaveWebhookRequest, SaveWebhookResponse>) {
const webhook = await sdk.automations.webhook.save(ctx.request.body) const webhook = await sdk.automations.webhook.save(ctx.request.body)
ctx.body = { ctx.body = {
message: "Webhook created successfully", message: "Webhook created successfully",
@ -34,21 +42,23 @@ export async function save(ctx: BBContext) {
} }
} }
export async function destroy(ctx: BBContext) { export async function destroy(ctx: Ctx<void, DeleteWebhookResponse>) {
ctx.body = await sdk.automations.webhook.destroy( ctx.body = await sdk.automations.webhook.destroy(
ctx.params.id, ctx.params.id,
ctx.params.rev ctx.params.rev
) )
} }
export async function buildSchema(ctx: BBContext) { export async function buildSchema(
ctx: Ctx<BuildWebhookSchemaRequest, BuildWebhookSchemaResponse>
) {
await context.doInAppContext(ctx.params.instance, async () => { await context.doInAppContext(ctx.params.instance, async () => {
const db = context.getAppDB() const db = context.getAppDB()
const webhook = (await db.get(ctx.params.id)) as Webhook const webhook = await db.get<Webhook>(ctx.params.id)
webhook.bodySchema = toJsonSchema(ctx.request.body) webhook.bodySchema = toJsonSchema(ctx.request.body)
// update the automation outputs // update the automation outputs
if (webhook.action.type === WebhookActionType.AUTOMATION) { if (webhook.action.type === WebhookActionType.AUTOMATION) {
let automation = (await db.get(webhook.action.target)) as Automation let automation = await db.get<Automation>(webhook.action.target)
const autoOutputs = automation.definition.trigger.schema.outputs const autoOutputs = automation.definition.trigger.schema.outputs
let properties = webhook.bodySchema.properties let properties = webhook.bodySchema.properties
// reset webhook outputs // reset webhook outputs
@ -67,17 +77,29 @@ export async function buildSchema(ctx: BBContext) {
}) })
} }
export async function trigger(ctx: BBContext) { export async function trigger(
ctx: Ctx<TriggerWebhookRequest, TriggerWebhookResponse>
) {
const prodAppId = dbCore.getProdAppID(ctx.params.instance) const prodAppId = dbCore.getProdAppID(ctx.params.instance)
const appNotDeployed = () => {
ctx.body = {
message: "Application not deployed yet.",
}
}
await context.doInAppContext(prodAppId, async () => { await context.doInAppContext(prodAppId, async () => {
try {
const db = context.getAppDB() const db = context.getAppDB()
const webhook = (await db.get(ctx.params.id)) as Webhook const webhook = await db.tryGet<Webhook>(ctx.params.id)
if (!webhook) {
return appNotDeployed()
}
// validate against the schema // validate against the schema
if (webhook.bodySchema) { if (webhook.bodySchema) {
validate(ctx.request.body, webhook.bodySchema) validate(ctx.request.body, webhook.bodySchema)
} }
const target = await db.get<Automation>(webhook.action.target) const target = await db.tryGet<Automation>(webhook.action.target)
if (!target) {
return appNotDeployed()
}
if (webhook.action.type === WebhookActionType.AUTOMATION) { if (webhook.action.type === WebhookActionType.AUTOMATION) {
// trigger with both the pure request and then expand it // trigger with both the pure request and then expand it
// incase the user has produced a schema to bind to // incase the user has produced a schema to bind to
@ -87,8 +109,10 @@ export async function trigger(ctx: BBContext) {
const response = await triggers.externalTrigger( const response = await triggers.externalTrigger(
target, target,
{ {
body: ctx.request.body, fields: {
...ctx.request.body, ...ctx.request.body,
body: ctx.request.body,
},
appId: prodAppId, appId: prodAppId,
}, },
{ getResponses: true } { getResponses: true }
@ -99,30 +123,22 @@ export async function trigger(ctx: BBContext) {
(step: any) => step.stepId === AutomationActionStepId.COLLECT (step: any) => step.stepId === AutomationActionStepId.COLLECT
) )
ctx.status = 200
ctx.body = collectedValue?.outputs ctx.body = collectedValue?.outputs
} else { } else {
ctx.throw(400, "Automation did not have a collect block.") ctx.throw(400, "Automation did not have a collect block.")
} }
} else { } else {
await triggers.externalTrigger(target, { await triggers.externalTrigger(target, {
body: ctx.request.body, fields: {
...ctx.request.body, ...ctx.request.body,
body: ctx.request.body,
},
appId: prodAppId, appId: prodAppId,
}) })
ctx.status = 200
ctx.body = { ctx.body = {
message: "Webhook trigger fired successfully", message: "Webhook trigger fired successfully",
} }
} }
} }
} catch (err: any) {
if (err.status === 404) {
ctx.status = 200
ctx.body = {
message: "Application not deployed yet.",
}
}
}
}) })
} }

View File

@ -58,12 +58,9 @@ if (apiEnabled()) {
}) })
) )
.use(pro.licensing()) .use(pro.licensing())
// @ts-ignore
.use(currentApp) .use(currentApp)
.use(auth.auditLog) .use(auth.auditLog)
// @ts-ignore
.use(migrations) .use(migrations)
// @ts-ignore
.use(cleanup) .use(cleanup)
// authenticated routes // authenticated routes

View File

@ -1,10 +0,0 @@
import Router from "@koa/router"
import * as controller from "../controllers/script"
import authorized from "../../middleware/authorized"
import { permissions } from "@budibase/backend-core"
const router: Router = new Router()
router.post("/api/script", authorized(permissions.BUILDER), controller.save)
export default router

View File

@ -1,5 +1,5 @@
import { isDevAppID, isProdAppID } from "../db/utils" import { isDevAppID, isProdAppID } from "../db/utils"
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
export enum AppType { export enum AppType {
DEV = "dev", DEV = "dev",
@ -7,7 +7,7 @@ export enum AppType {
} }
export function middleware({ appType }: { appType?: AppType } = {}) { export function middleware({ appType }: { appType?: AppType } = {}) {
return (ctx: BBContext, next: any) => { return (ctx: Ctx, next: any) => {
const appId = ctx.appId const appId = ctx.appId
if (appType === AppType.DEV && appId && !isDevAppID(appId)) { if (appType === AppType.DEV && appId && !isDevAppID(appId)) {
ctx.throw(400, "Only apps in development support this endpoint") ctx.throw(400, "Only apps in development support this endpoint")

View File

@ -1,8 +1,9 @@
import { UserCtx } from "@budibase/types" import { UserCtx } from "@budibase/types"
import { checkMissingMigrations } from "../appMigrations" import { checkMissingMigrations } from "../appMigrations"
import env from "../environment" import env from "../environment"
import type { Middleware, Next } from "koa"
export default async (ctx: UserCtx, next: any) => { const middleware = (async (ctx: UserCtx, next: Next) => {
const { appId } = ctx const { appId } = ctx
// migrations can be disabled via environment variable if you // migrations can be disabled via environment variable if you
@ -16,4 +17,6 @@ export default async (ctx: UserCtx, next: any) => {
} }
return checkMissingMigrations(ctx, next, appId) return checkMissingMigrations(ctx, next, appId)
} }) as Middleware
export default middleware

View File

@ -1,8 +1,9 @@
import { Ctx } from "@budibase/types" import { Ctx } from "@budibase/types"
import { context } from "@budibase/backend-core" import { context } from "@budibase/backend-core"
import { tracer } from "dd-trace" import { tracer } from "dd-trace"
import type { Middleware, Next } from "koa"
export default async (ctx: Ctx, next: any) => { const middleware = (async (ctx: Ctx, next: Next) => {
const resp = await next() const resp = await next()
const current = context.getCurrentContext() const current = context.getCurrentContext()
@ -30,4 +31,6 @@ export default async (ctx: Ctx, next: any) => {
} }
return resp return resp
} }) as Middleware
export default middleware

View File

@ -13,8 +13,9 @@ import env from "../environment"
import { isWebhookEndpoint, isBrowser, isApiKey } from "./utils" import { isWebhookEndpoint, isBrowser, isApiKey } from "./utils"
import { UserCtx, ContextUser } from "@budibase/types" import { UserCtx, ContextUser } from "@budibase/types"
import tracer from "dd-trace" import tracer from "dd-trace"
import type { Middleware, Next } from "koa"
export default async (ctx: UserCtx, next: any) => { const middleware = (async (ctx: UserCtx, next: Next) => {
// try to get the appID from the request // try to get the appID from the request
let requestAppId = await utils.getAppIdFromCtx(ctx) let requestAppId = await utils.getAppIdFromCtx(ctx)
if (!requestAppId) { if (!requestAppId) {
@ -116,4 +117,6 @@ export default async (ctx: UserCtx, next: any) => {
return next() return next()
}) })
} }) as Middleware
export default middleware

View File

@ -1,9 +1,9 @@
import Joi from "joi" import Joi from "joi"
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
function validate(schema: Joi.Schema, property: string) { function validate(schema: Joi.Schema, property: string) {
// Return a Koa middleware function // Return a Koa middleware function
return (ctx: BBContext, next: any) => { return (ctx: Ctx, next: any) => {
if (!schema) { if (!schema) {
return next() return next()
} }

View File

@ -1,4 +1,4 @@
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
export class ResourceIdGetter { export class ResourceIdGetter {
parameter: string parameter: string
@ -26,7 +26,7 @@ export class ResourceIdGetter {
const parameter = this.parameter, const parameter = this.parameter,
main = this.main, main = this.main,
sub = this.sub sub = this.sub
return (ctx: BBContext, next: any) => { return (ctx: Ctx, next: any) => {
// @ts-ignore // @ts-ignore
const request = ctx.request[parameter] || ctx[parameter] const request = ctx.request[parameter] || ctx[parameter]
if (request == null) { if (request == null) {

View File

@ -1,9 +1,9 @@
import env from "../environment" import env from "../environment"
import { BBContext } from "@budibase/types" import { Ctx } from "@budibase/types"
// if added as a middleware will stop requests unless builder is in self host mode // if added as a middleware will stop requests unless builder is in self host mode
// or cloud is in self host // or cloud is in self host
export default async (ctx: BBContext, next: any) => { export default async (ctx: Ctx, next: any) => {
if (env.SELF_HOSTED) { if (env.SELF_HOSTED) {
await next() await next()
return return

View File

@ -9,7 +9,7 @@ import {
Database, Database,
INTERNAL_TABLE_SOURCE_ID, INTERNAL_TABLE_SOURCE_ID,
Table, Table,
TableResponse, FindTableResponse,
TableSourceType, TableSourceType,
TableViewsResponse, TableViewsResponse,
} from "@budibase/types" } from "@budibase/types"
@ -173,7 +173,9 @@ export async function getTables(tableIds: string[]): Promise<Table[]> {
return await processTables(tables) return await processTables(tables)
} }
export async function enrichViewSchemas(table: Table): Promise<TableResponse> { export async function enrichViewSchemas(
table: Table
): Promise<FindTableResponse> {
const views = [] const views = []
for (const view of Object.values(table.views ?? [])) { for (const view of Object.values(table.views ?? [])) {
if (sdk.views.isV2(view)) { if (sdk.views.isV2(view)) {

View File

@ -3,8 +3,8 @@ import {
BulkImportResponse, BulkImportResponse,
CsvToJsonRequest, CsvToJsonRequest,
CsvToJsonResponse, CsvToJsonResponse,
MigrateRequest, MigrateTableRequest,
MigrateResponse, MigrateTableResponse,
SaveTableRequest, SaveTableRequest,
SaveTableResponse, SaveTableResponse,
Table, Table,
@ -38,13 +38,16 @@ export class TableAPI extends TestAPI {
migrate = async ( migrate = async (
tableId: string, tableId: string,
data: MigrateRequest, data: MigrateTableRequest,
expectations?: Expectations expectations?: Expectations
): Promise<MigrateResponse> => { ): Promise<MigrateTableResponse> => {
return await this._post<MigrateResponse>(`/api/tables/${tableId}/migrate`, { return await this._post<MigrateTableResponse>(
`/api/tables/${tableId}/migrate`,
{
body: data, body: data,
expectations, expectations,
}) }
)
} }
import = async ( import = async (

View File

@ -1,5 +1,5 @@
import type { PlanType } from "../../sdk" import type { PlanType } from "../../../sdk"
import type { Layout, App, Screen } from "../../documents" import type { Layout, App, Screen } from "../../../documents"
import { ReadStream } from "fs" import { ReadStream } from "fs"
export interface SyncAppResponse { export interface SyncAppResponse {

View File

@ -1,9 +1,14 @@
import { import {
Automation,
AutomationActionStepId, AutomationActionStepId,
AutomationLogPage,
AutomationStatus,
AutomationStepDefinition, AutomationStepDefinition,
AutomationTriggerDefinition, AutomationTriggerDefinition,
AutomationTriggerStepId, AutomationTriggerStepId,
Row,
} from "../../../documents" } from "../../../documents"
import { DocumentDestroyResponse } from "@budibase/nano"
export type GetAutomationTriggerDefinitionsResponse = Record< export type GetAutomationTriggerDefinitionsResponse = Record<
keyof typeof AutomationTriggerStepId, keyof typeof AutomationTriggerStepId,
@ -19,3 +24,54 @@ export interface GetAutomationStepDefinitionsResponse {
trigger: GetAutomationTriggerDefinitionsResponse trigger: GetAutomationTriggerDefinitionsResponse
action: GetAutomationActionDefinitionsResponse action: GetAutomationActionDefinitionsResponse
} }
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<string, any>
// time in seconds
timeout: number
}
export type TriggerAutomationResponse = Record<string, any> | undefined
export interface TestAutomationRequest {
id?: string
revision?: string
fields: Record<string, any>
row?: Row
}
export interface TestAutomationResponse {}

View File

@ -1,4 +1,4 @@
import { DeploymentDoc, DeploymentStatus } from "../../documents" import { DeploymentDoc, DeploymentStatus } from "../../../documents"
export interface PublishAppResponse extends DeploymentDoc {} export interface PublishAppResponse extends DeploymentDoc {}

View File

@ -13,3 +13,9 @@ export * from "./integration"
export * from "./metadata" export * from "./metadata"
export * from "./query" export * from "./query"
export * from "./screen" export * from "./screen"
export * from "./application"
export * from "./layout"
export * from "./deployment"
export * from "./role"
export * from "./webhook"
export * from "./static"

View File

@ -1,4 +1,4 @@
import { Layout } from "../../documents" import { Layout } from "../../../documents"
export interface SaveLayoutRequest extends Layout {} export interface SaveLayoutRequest extends Layout {}

View File

@ -1,5 +1,5 @@
import { Role, RoleUIMetadata } from "../../documents" import { Role, RoleUIMetadata } from "../../../documents"
import { PermissionLevel, BuiltinPermissionID } from "../../sdk" import { PermissionLevel, BuiltinPermissionID } from "../../../sdk"
export interface SaveRoleRequest { export interface SaveRoleRequest {
_id?: string _id?: string

View File

@ -1,4 +1,4 @@
import { ScreenRoutingJson } from "../../../documents" import { ScreenRoutingJson, Screen } from "../../../documents"
export interface FetchScreenRoutingResponse { export interface FetchScreenRoutingResponse {
routes: ScreenRoutingJson routes: ScreenRoutingJson
@ -6,3 +6,12 @@ export interface FetchScreenRoutingResponse {
export interface FetchClientScreenRoutingResponse export interface FetchClientScreenRoutingResponse
extends FetchScreenRoutingResponse {} extends FetchScreenRoutingResponse {}
export type FetchScreenResponse = Screen[]
export interface SaveScreenRequest extends Screen {}
export interface SaveScreenResponse extends Screen {}
export interface DeleteScreenResponse {
message: string
}

View File

@ -0,0 +1,25 @@
import { App } from "../../../documents"
import stream from "node:stream"
export interface ToggleBetaFeatureResponse {
message: string
}
export type ServeAppResponse = string
interface BuilderPreview extends App {
builderPreview: boolean
}
export type ServeBuilderPreviewResponse = BuilderPreview | string
export type ServeClientLibraryResponse = stream.Readable
export interface GetSignedUploadUrlRequest {
bucket: string
key: string
}
export interface GetSignedUploadUrlResponse {
signedUrl?: string
publicUrl?: string
}

View File

@ -3,33 +3,30 @@ import { ViewV2Enriched } from "../../../sdk"
export type TableViewsResponse = { [key: string]: View | ViewV2Enriched } export type TableViewsResponse = { [key: string]: View | ViewV2Enriched }
export interface TableResponse extends Table { export interface FindTableResponse extends Table {
views?: TableViewsResponse views?: TableViewsResponse
} }
export type FetchTablesResponse = TableResponse[] export type FetchTablesResponse = FindTableResponse[]
export interface SaveTableRequest extends TableRequest { export interface SaveTableRequest extends TableRequest {
rows?: Row[] rows?: Row[]
} }
export type SaveTableResponse = Table export type SaveTableResponse = Table
export interface BulkImportRequest { export interface BulkImportRequest {
rows: Row[] rows: Row[]
identifierFields?: Array<string> identifierFields?: Array<string>
} }
export interface BulkImportResponse { export interface BulkImportResponse {
message: string message: string
} }
export interface MigrateRequest { export interface MigrateTableRequest {
oldColumn: string oldColumn: string
newColumn: string newColumn: string
} }
export interface MigrateTableResponse {
export interface MigrateResponse {
message: string message: string
} }
@ -37,12 +34,10 @@ export interface ValidateNewTableImportRequest {
rows: Row[] rows: Row[]
schema: TableSchema schema: TableSchema
} }
export interface ValidateTableImportRequest { export interface ValidateTableImportRequest {
tableId?: string tableId?: string
rows: Row[] rows: Row[]
} }
export interface ValidateTableImportResponse { export interface ValidateTableImportResponse {
schemaValidation: { schemaValidation: {
[field: string]: boolean [field: string]: boolean
@ -55,5 +50,8 @@ export interface ValidateTableImportResponse {
export interface CsvToJsonRequest { export interface CsvToJsonRequest {
csvString: string csvString: string
} }
export type CsvToJsonResponse = any[] export type CsvToJsonResponse = any[]
export interface DeleteTableResponse {
message: string
}

View File

@ -1,11 +1,27 @@
import { ContextUserMetadata } from "../../../" import { ContextUserMetadata, Flags, UserMetadata } from "../../../"
import { DocumentInsertResponse } from "@budibase/nano"
export type FetchUserMetadataResponse = ContextUserMetadata[] export type FetchUserMetadataResponse = ContextUserMetadata[]
export type FindUserMetadataResponse = ContextUserMetadata export type FindUserMetadataResponse = ContextUserMetadata
export interface SetFlagRequest { export interface SetUserFlagRequest {
flag: string flag: string
value: any value: any
} }
export interface SetUserFlagResponse {
message: string
}
export interface GetUserFlagsResponse extends Flags {}
export type AppSelfResponse = ContextUserMetadata | {} export type AppSelfResponse = ContextUserMetadata | {}
export interface UpdateSelfMetadataRequest extends UserMetadata {}
export interface UpdateSelfMetadataResponse extends DocumentInsertResponse {}
export interface UpdateUserMetadataRequest extends UserMetadata {}
export interface UpdateUserMetadataResponse extends DocumentInsertResponse {}
export interface DeleteUserMetadataResponse {
message: string
}

View File

@ -14,5 +14,7 @@ export interface ViewFetchResponseEnriched {
} }
export interface CreateViewRequest extends Omit<ViewV2, "version" | "id"> {} export interface CreateViewRequest extends Omit<ViewV2, "version" | "id"> {}
export interface CreateViewResponse extends ViewResponse {}
export interface UpdateViewRequest extends ViewV2 {} export interface UpdateViewRequest extends ViewV2 {}
export interface UpdateViewResponse extends ViewResponse {}

View File

@ -0,0 +1,21 @@
import { Webhook } from "../../../documents"
import { DocumentDestroyResponse, DocumentInsertResponse } from "@budibase/nano"
export type FetchWebhooksResponse = Webhook[]
export interface SaveWebhookRequest extends Webhook {}
export interface SaveWebhookResponse {
message: string
webhook: Webhook
}
export interface DeleteWebhookResponse extends DocumentDestroyResponse {}
export interface BuildWebhookSchemaRequest extends Record<string, any> {}
export interface BuildWebhookSchemaResponse extends DocumentInsertResponse {}
export interface TriggerWebhookRequest {}
export type TriggerWebhookResponse =
| Record<string, any>
| { message: string }
| undefined

View File

@ -1,58 +0,0 @@
import { DocumentDestroyResponse } from "@budibase/nano"
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<string, any>
// time in seconds
timeout: number
}
export type TriggerAutomationResponse = Record<string, any> | undefined
export interface TestAutomationRequest {
id?: string
revision?: string
fields: Record<string, any>
row?: Row
}
export interface TestAutomationResponse {}

View File

@ -1,4 +1,3 @@
export * from "./application"
export * from "./analytics" export * from "./analytics"
export * from "./auth" export * from "./auth"
export * from "./user" export * from "./user"
@ -11,10 +10,7 @@ export * from "./global"
export * from "./pagination" export * from "./pagination"
export * from "./searchFilter" export * from "./searchFilter"
export * from "./cookies" export * from "./cookies"
export * from "./automation"
export * from "./layout"
export * from "./role"
export * from "./plugins" export * from "./plugins"
export * from "./apikeys" export * from "./apikeys"
export * from "./deployment"
export * from "./dev" export * from "./dev"
export * from "./template"

View File

@ -0,0 +1,21 @@
export enum TemplateType {
APP = "app",
}
export interface TemplateMetadata {
background: string
icon: string
category: string
description: string
name: string
url: string
type: TemplateType
key: string
image: string
}
export type FetchTemplateResponse = TemplateMetadata[]
export interface DownloadTemplateResponse {
message: string
}

View File

@ -1,4 +1,4 @@
import { BBContext } from "./koa" import { Ctx } from "./koa"
import { Hosting } from "./hosting" import { Hosting } from "./hosting"
export interface AuthToken { export interface AuthToken {
@ -32,7 +32,7 @@ export interface ScannedSession {
} }
export interface PlatformLogoutOpts { export interface PlatformLogoutOpts {
ctx: BBContext ctx: Ctx
userId: string userId: string
keepActiveSession?: boolean keepActiveSession?: boolean
} }