@budibase/server 1.3.18 → 1.3.19-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__mocks__/mongodb.ts +1 -1
- package/builder/assets/{index.a70e216a.css → index.3850883f.css} +2 -2
- package/builder/assets/index.fdade753.js +995 -0
- package/builder/index.html +2 -4
- package/coverage/clover.xml +409 -361
- package/coverage/coverage-final.json +18 -18
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
- package/coverage/lcov-report/api/controllers/component.js.html +68 -11
- package/coverage/lcov-report/api/controllers/datasource.js.html +73 -34
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +38 -38
- package/coverage/lcov-report/api/controllers/integration.js.html +6 -6
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +2 -2
- package/coverage/lcov-report/api/controllers/row/index.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/screen.js.html +207 -12
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +12 -12
- package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +1 -1
- package/coverage/lcov-report/api/routes/integration.js.html +1 -1
- package/coverage/lcov-report/api/routes/layout.js.html +1 -1
- package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
- package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +1 -1
- package/coverage/lcov-report/api/routes/role.js.html +1 -1
- package/coverage/lcov-report/api/routes/routing.js.html +1 -1
- package/coverage/lcov-report/api/routes/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.js.html +1 -1
- package/coverage/lcov-report/api/routes/table.js.html +2 -2
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +1 -1
- package/coverage/lcov-report/api/routes/utils/index.html +5 -5
- package/coverage/lcov-report/api/routes/utils/validators.js.html +9 -6
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +1 -1
- package/coverage/lcov-report/automations/index.js.html +1 -1
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +1 -1
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +1 -1
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +18 -18
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +2 -2
- package/coverage/lcov-report/db/utils.js.html +56 -20
- package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
- package/coverage/lcov-report/events/index.html +1 -1
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +1 -1
- package/coverage/lcov-report/index.html +30 -30
- package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
- package/coverage/lcov-report/integrations/tests/index.html +1 -1
- package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
- package/coverage/lcov-report/middleware/builder.js.html +12 -12
- package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +2 -2
- package/coverage/lcov-report/utilities/budibaseDir.js.html +3 -3
- package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
- package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
- package/coverage/lcov-report/utilities/global.js.html +16 -16
- package/coverage/lcov-report/utilities/index.html +1 -1
- package/coverage/lcov-report/utilities/index.js.html +24 -24
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
- package/coverage/lcov-report/utilities/queue/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +2 -2
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
- package/coverage/lcov.info +725 -623
- package/dist/api/controllers/application.js +5 -4
- package/dist/api/controllers/component.js +14 -1
- package/dist/api/controllers/datasource.js +21 -8
- package/dist/api/controllers/integration.js +4 -4
- package/dist/api/controllers/plugin/file.js +24 -0
- package/dist/api/controllers/plugin/github.js +69 -0
- package/dist/api/controllers/plugin/index.js +197 -0
- package/dist/api/controllers/plugin/npm.js +58 -0
- package/dist/api/controllers/plugin/uploaders.js +11 -0
- package/dist/api/controllers/plugin/url.js +24 -0
- package/dist/api/controllers/plugin/utils.js +26 -0
- package/dist/api/controllers/row/external.js +1 -1
- package/dist/api/controllers/screen.js +52 -2
- package/dist/api/controllers/static/index.js +1 -0
- package/dist/api/controllers/static/templates/BudibaseApp.svelte +10 -0
- package/dist/api/controllers/static/templates/preview.hbs +5 -1
- package/dist/api/routes/application.js +3 -2
- package/dist/api/routes/index.js +2 -0
- package/dist/api/routes/plugin.js +39 -0
- package/dist/api/routes/public/tables.js +1 -1
- package/dist/api/routes/table.js +1 -1
- package/dist/api/routes/utils/validators.js +2 -1
- package/dist/app.js +11 -0
- package/dist/db/utils.js +10 -1
- package/dist/environment.js +1 -0
- package/dist/integrations/airtable.js +126 -129
- package/dist/integrations/arangodb.js +86 -89
- package/dist/integrations/base/query.js +2 -2
- package/dist/integrations/base/sqlTable.js +3 -1
- package/dist/integrations/couchdb.js +80 -83
- package/dist/integrations/dynamodb.js +161 -164
- package/dist/integrations/elasticsearch.js +135 -138
- package/dist/integrations/firebase.js +154 -157
- package/dist/integrations/googlesheets.js +323 -327
- package/dist/integrations/index.js +99 -51
- package/dist/integrations/microsoftSqlServer.js +240 -243
- package/dist/integrations/mongodb.js +239 -242
- package/dist/integrations/mysql.js +215 -219
- package/dist/integrations/oracle.js +318 -322
- package/dist/integrations/postgres.js +262 -265
- package/dist/integrations/redis.js +134 -139
- package/dist/integrations/rest.js +289 -292
- package/dist/integrations/s3.js +61 -64
- package/dist/integrations/snowflake.js +83 -86
- package/dist/package.json +9 -6
- package/dist/tests/utilities/TestConfiguration.js +1 -1
- package/dist/threads/query.js +2 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utilities/fileSystem/index.js +110 -1
- package/dist/watch.js +77 -0
- package/dist/websocket.js +22 -0
- package/package.json +10 -7
- package/scripts/dev/manage.js +1 -0
- package/specs/openapi.json +3 -3
- package/specs/openapi.yaml +3 -3
- package/specs/resources/query.js +1 -1
- package/src/api/controllers/application.ts +1 -1
- package/src/api/controllers/component.js +21 -2
- package/src/api/controllers/datasource.js +21 -8
- package/src/api/controllers/integration.js +4 -4
- package/src/api/controllers/plugin/file.ts +15 -0
- package/src/api/controllers/plugin/github.ts +75 -0
- package/src/api/controllers/plugin/index.ts +212 -0
- package/src/api/controllers/plugin/npm.ts +56 -0
- package/src/api/controllers/plugin/uploaders.ts +4 -0
- package/src/api/controllers/plugin/url.ts +12 -0
- package/src/api/controllers/plugin/utils.ts +19 -0
- package/src/api/controllers/row/external.js +1 -1
- package/src/api/controllers/screen.js +66 -1
- package/src/api/controllers/static/index.ts +1 -0
- package/src/api/controllers/static/templates/BudibaseApp.svelte +10 -0
- package/src/api/controllers/static/templates/preview.hbs +5 -1
- package/src/api/routes/application.ts +13 -2
- package/src/api/routes/index.ts +2 -0
- package/src/api/routes/plugin.ts +14 -0
- package/src/api/routes/public/tables.ts +1 -1
- package/src/api/routes/table.js +1 -1
- package/src/api/routes/tests/query.spec.js +8 -25
- package/src/api/routes/utils/validators.js +2 -1
- package/src/app.ts +14 -0
- package/src/db/utils.js +12 -0
- package/src/definitions/openapi.ts +3 -3
- package/src/environment.js +1 -0
- package/src/integrations/airtable.ts +116 -118
- package/src/integrations/arangodb.ts +87 -89
- package/src/integrations/base/query.ts +2 -2
- package/src/integrations/base/sqlTable.ts +3 -1
- package/src/integrations/couchdb.ts +83 -89
- package/src/integrations/dynamodb.ts +173 -175
- package/src/integrations/elasticsearch.ts +120 -122
- package/src/integrations/firebase.ts +157 -159
- package/src/integrations/googlesheets.ts +328 -338
- package/src/integrations/index.ts +64 -21
- package/src/integrations/microsoftSqlServer.ts +249 -251
- package/src/integrations/mongodb.ts +261 -258
- package/src/integrations/mysql.ts +229 -234
- package/src/integrations/oracle.ts +373 -380
- package/src/integrations/postgres.ts +264 -268
- package/src/integrations/redis.ts +128 -132
- package/src/integrations/rest.ts +324 -329
- package/src/integrations/s3.ts +68 -71
- package/src/integrations/snowflake.ts +80 -82
- package/src/integrations/tests/{airtable.spec.js → airtable.spec.ts} +21 -18
- package/src/integrations/tests/{arangodb.spec.js → arangodb.spec.ts} +12 -9
- package/src/integrations/tests/{couchdb.spec.js → couchdb.spec.ts} +33 -27
- package/src/integrations/tests/{dynamodb.spec.js → dynamodb.spec.ts} +45 -41
- package/src/integrations/tests/{elasticsearch.spec.js → elasticsearch.spec.ts} +22 -21
- package/src/integrations/tests/{firebase.spec.js → firebase.spec.ts} +33 -28
- package/src/integrations/tests/{microsoftSqlServer.spec.js → microsoftSqlServer.spec.ts} +12 -11
- package/src/integrations/tests/{mongo.spec.js → mongo.spec.ts} +46 -35
- package/src/integrations/tests/{mysql.spec.js → mysql.spec.ts} +17 -15
- package/src/integrations/tests/{oracle.spec.js → oracle.spec.ts} +19 -17
- package/src/integrations/tests/{postgres.spec.js → postgres.spec.ts} +19 -17
- package/src/integrations/tests/{redis.spec.js → redis.spec.ts} +27 -18
- package/src/integrations/tests/{rest.spec.js → rest.spec.ts} +22 -14
- package/src/integrations/tests/{s3.spec.js → s3.spec.ts} +10 -8
- package/src/integrations/tests/{sql.spec.js → sql.spec.ts} +228 -177
- package/src/module.d.ts +2 -0
- package/src/tests/utilities/TestConfiguration.js +1 -1
- package/src/threads/query.ts +2 -2
- package/src/utilities/fileSystem/index.js +129 -0
- package/src/watch.ts +38 -0
- package/src/websocket.ts +26 -0
- package/builder/assets/index.a934251d.js +0 -876
- package/builder/assets/vendor.5e1fe644.css +0 -1
- package/builder/assets/vendor.67dbd8fa.js +0 -248
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { ObjectStoreBuckets } from "../../../constants"
|
|
2
|
+
import { loadJSFile } from "../../../utilities/fileSystem"
|
|
3
|
+
import { npmUpload, urlUpload, githubUpload, fileUpload } from "./uploaders"
|
|
4
|
+
import { getGlobalDB } from "@budibase/backend-core/tenancy"
|
|
5
|
+
import { validate } from "@budibase/backend-core/plugins"
|
|
6
|
+
import { generatePluginID, getPluginParams } from "../../../db/utils"
|
|
7
|
+
import {
|
|
8
|
+
uploadDirectory,
|
|
9
|
+
deleteFolder,
|
|
10
|
+
} from "@budibase/backend-core/objectStore"
|
|
11
|
+
import { PluginType, FileType, PluginSource } from "@budibase/types"
|
|
12
|
+
import env from "../../../environment"
|
|
13
|
+
import { ClientAppSocket } from "../../../websocket"
|
|
14
|
+
|
|
15
|
+
export async function getPlugins(type?: PluginType) {
|
|
16
|
+
const db = getGlobalDB()
|
|
17
|
+
const response = await db.allDocs(
|
|
18
|
+
getPluginParams(null, {
|
|
19
|
+
include_docs: true,
|
|
20
|
+
})
|
|
21
|
+
)
|
|
22
|
+
const plugins = response.rows.map((row: any) => row.doc)
|
|
23
|
+
if (type) {
|
|
24
|
+
return plugins.filter((plugin: any) => plugin.schema?.type === type)
|
|
25
|
+
} else {
|
|
26
|
+
return plugins
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function upload(ctx: any) {
|
|
31
|
+
const plugins: FileType[] =
|
|
32
|
+
ctx.request.files.file.length > 1
|
|
33
|
+
? Array.from(ctx.request.files.file)
|
|
34
|
+
: [ctx.request.files.file]
|
|
35
|
+
try {
|
|
36
|
+
let docs = []
|
|
37
|
+
// can do single or multiple plugins
|
|
38
|
+
for (let plugin of plugins) {
|
|
39
|
+
const doc = await processPlugin(plugin, PluginSource.FILE)
|
|
40
|
+
docs.push(doc)
|
|
41
|
+
}
|
|
42
|
+
ctx.body = {
|
|
43
|
+
message: "Plugin(s) uploaded successfully",
|
|
44
|
+
plugins: docs,
|
|
45
|
+
}
|
|
46
|
+
} catch (err: any) {
|
|
47
|
+
const errMsg = err?.message ? err?.message : err
|
|
48
|
+
|
|
49
|
+
ctx.throw(400, `Failed to import plugin: ${errMsg}`)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function create(ctx: any) {
|
|
54
|
+
const { source, url, headers, githubToken } = ctx.request.body
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
let metadata
|
|
58
|
+
let directory
|
|
59
|
+
// Generating random name as a backup and needed for url
|
|
60
|
+
let name = "PLUGIN_" + Math.floor(100000 + Math.random() * 900000)
|
|
61
|
+
|
|
62
|
+
switch (source) {
|
|
63
|
+
case PluginSource.NPM:
|
|
64
|
+
const { metadata: metadataNpm, directory: directoryNpm } =
|
|
65
|
+
await npmUpload(url, name)
|
|
66
|
+
metadata = metadataNpm
|
|
67
|
+
directory = directoryNpm
|
|
68
|
+
break
|
|
69
|
+
case PluginSource.GITHUB:
|
|
70
|
+
const { metadata: metadataGithub, directory: directoryGithub } =
|
|
71
|
+
await githubUpload(url, name, githubToken)
|
|
72
|
+
metadata = metadataGithub
|
|
73
|
+
directory = directoryGithub
|
|
74
|
+
break
|
|
75
|
+
case PluginSource.URL:
|
|
76
|
+
const headersObj = headers || {}
|
|
77
|
+
const { metadata: metadataUrl, directory: directoryUrl } =
|
|
78
|
+
await urlUpload(url, name, headersObj)
|
|
79
|
+
metadata = metadataUrl
|
|
80
|
+
directory = directoryUrl
|
|
81
|
+
break
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
validate(metadata?.schema)
|
|
85
|
+
|
|
86
|
+
// Only allow components in cloud
|
|
87
|
+
if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
"Only component plugins are supported outside of self-host"
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const doc = await storePlugin(metadata, directory, source)
|
|
94
|
+
|
|
95
|
+
ctx.body = {
|
|
96
|
+
message: "Plugin uploaded successfully",
|
|
97
|
+
plugins: [doc],
|
|
98
|
+
}
|
|
99
|
+
} catch (err: any) {
|
|
100
|
+
const errMsg = err?.message ? err?.message : err
|
|
101
|
+
|
|
102
|
+
ctx.throw(400, `Failed to import plugin: ${errMsg}`)
|
|
103
|
+
}
|
|
104
|
+
ctx.status = 200
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function fetch(ctx: any) {
|
|
108
|
+
ctx.body = await getPlugins()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export async function destroy(ctx: any) {
|
|
112
|
+
const db = getGlobalDB()
|
|
113
|
+
const { pluginId } = ctx.params
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const plugin = await db.get(pluginId)
|
|
117
|
+
const bucketPath = `${plugin.name}/`
|
|
118
|
+
await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath)
|
|
119
|
+
|
|
120
|
+
await db.remove(pluginId, plugin._rev)
|
|
121
|
+
} catch (err: any) {
|
|
122
|
+
const errMsg = err?.message ? err?.message : err
|
|
123
|
+
|
|
124
|
+
ctx.throw(400, `Failed to delete plugin: ${errMsg}`)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
ctx.message = `Plugin ${ctx.params.pluginId} deleted.`
|
|
128
|
+
ctx.status = 200
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function storePlugin(
|
|
132
|
+
metadata: any,
|
|
133
|
+
directory: any,
|
|
134
|
+
source?: string
|
|
135
|
+
) {
|
|
136
|
+
const db = getGlobalDB()
|
|
137
|
+
const version = metadata.package.version,
|
|
138
|
+
name = metadata.package.name,
|
|
139
|
+
description = metadata.package.description,
|
|
140
|
+
hash = metadata.schema.hash
|
|
141
|
+
|
|
142
|
+
// first open the tarball into tmp directory
|
|
143
|
+
const bucketPath = `${name}/`
|
|
144
|
+
const files = await uploadDirectory(
|
|
145
|
+
ObjectStoreBuckets.PLUGINS,
|
|
146
|
+
directory,
|
|
147
|
+
bucketPath
|
|
148
|
+
)
|
|
149
|
+
const jsFile = files.find((file: any) => file.name.endsWith(".js"))
|
|
150
|
+
if (!jsFile) {
|
|
151
|
+
throw new Error(`Plugin missing .js file.`)
|
|
152
|
+
}
|
|
153
|
+
// validate the JS for a datasource
|
|
154
|
+
if (metadata.schema.type === PluginType.DATASOURCE) {
|
|
155
|
+
const js = loadJSFile(directory, jsFile.name)
|
|
156
|
+
// TODO: this isn't safe - but we need full node environment
|
|
157
|
+
// in future we should do this in a thread for safety
|
|
158
|
+
try {
|
|
159
|
+
eval(js)
|
|
160
|
+
} catch (err: any) {
|
|
161
|
+
const message = err?.message ? err.message : JSON.stringify(err)
|
|
162
|
+
throw new Error(`JS invalid: ${message}`)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const jsFileName = jsFile.name
|
|
166
|
+
const pluginId = generatePluginID(name)
|
|
167
|
+
|
|
168
|
+
// overwrite existing docs entirely if they exist
|
|
169
|
+
let rev
|
|
170
|
+
try {
|
|
171
|
+
const existing = await db.get(pluginId)
|
|
172
|
+
rev = existing._rev
|
|
173
|
+
} catch (err) {
|
|
174
|
+
rev = undefined
|
|
175
|
+
}
|
|
176
|
+
let doc = {
|
|
177
|
+
_id: pluginId,
|
|
178
|
+
_rev: rev,
|
|
179
|
+
...metadata,
|
|
180
|
+
name,
|
|
181
|
+
version,
|
|
182
|
+
hash,
|
|
183
|
+
description,
|
|
184
|
+
jsUrl: `${bucketPath}${jsFileName}`,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (source) {
|
|
188
|
+
doc = {
|
|
189
|
+
...doc,
|
|
190
|
+
source,
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const response = await db.put(doc)
|
|
195
|
+
ClientAppSocket.emit("plugin-update", { name, hash })
|
|
196
|
+
return {
|
|
197
|
+
...doc,
|
|
198
|
+
_rev: response.rev,
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export async function processPlugin(plugin: FileType, source?: string) {
|
|
203
|
+
const { metadata, directory } = await fileUpload(plugin)
|
|
204
|
+
validate(metadata?.schema)
|
|
205
|
+
|
|
206
|
+
// Only allow components in cloud
|
|
207
|
+
if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
|
|
208
|
+
throw new Error("Only component plugins are supported outside of self-host")
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return await storePlugin(metadata, directory, source)
|
|
212
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getPluginMetadata,
|
|
3
|
+
findFileRec,
|
|
4
|
+
extractTarball,
|
|
5
|
+
deleteFolderFileSystem,
|
|
6
|
+
} from "../../../utilities/fileSystem"
|
|
7
|
+
import fetch from "node-fetch"
|
|
8
|
+
import { join } from "path"
|
|
9
|
+
import { downloadUnzipTarball } from "./utils"
|
|
10
|
+
|
|
11
|
+
export async function npmUpload(url: string, name: string, headers = {}) {
|
|
12
|
+
let npmTarballUrl = url
|
|
13
|
+
let pluginName = name
|
|
14
|
+
|
|
15
|
+
if (
|
|
16
|
+
!npmTarballUrl.includes("https://www.npmjs.com") &&
|
|
17
|
+
!npmTarballUrl.includes("https://registry.npmjs.org")
|
|
18
|
+
) {
|
|
19
|
+
throw new Error("The plugin origin must be from NPM")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!npmTarballUrl.includes(".tgz")) {
|
|
23
|
+
const npmPackageURl = url.replace(
|
|
24
|
+
"https://www.npmjs.com/package/",
|
|
25
|
+
"https://registry.npmjs.org/"
|
|
26
|
+
)
|
|
27
|
+
const response = await fetch(npmPackageURl)
|
|
28
|
+
if (response.status !== 200) {
|
|
29
|
+
throw new Error("NPM Package not found")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let npmDetails = await response.json()
|
|
33
|
+
pluginName = npmDetails.name
|
|
34
|
+
const npmVersion = npmDetails["dist-tags"].latest
|
|
35
|
+
npmTarballUrl = npmDetails?.versions?.[npmVersion]?.dist?.tarball
|
|
36
|
+
|
|
37
|
+
if (!npmTarballUrl) {
|
|
38
|
+
throw new Error("NPM tarball url not found")
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const path = await downloadUnzipTarball(npmTarballUrl, pluginName, headers)
|
|
43
|
+
const tarballPluginFile = findFileRec(path, ".tar.gz")
|
|
44
|
+
if (!tarballPluginFile) {
|
|
45
|
+
throw new Error("Tarball plugin file not found")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await extractTarball(tarballPluginFile, path)
|
|
50
|
+
deleteFolderFileSystem(join(path, "package"))
|
|
51
|
+
} catch (err: any) {
|
|
52
|
+
throw new Error(err)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return await getPluginMetadata(path)
|
|
56
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { downloadUnzipTarball } from "./utils"
|
|
2
|
+
import { getPluginMetadata } from "../../../utilities/fileSystem"
|
|
3
|
+
|
|
4
|
+
export async function urlUpload(url: string, name = "", headers = {}) {
|
|
5
|
+
if (!url.includes(".tar.gz")) {
|
|
6
|
+
throw new Error("Plugin must be compressed into a gzipped tarball.")
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const path = await downloadUnzipTarball(url, name, headers)
|
|
10
|
+
|
|
11
|
+
return await getPluginMetadata(path)
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createTempFolder,
|
|
3
|
+
downloadTarballDirect,
|
|
4
|
+
} from "../../../utilities/fileSystem"
|
|
5
|
+
|
|
6
|
+
export async function downloadUnzipTarball(
|
|
7
|
+
url: string,
|
|
8
|
+
name: string,
|
|
9
|
+
headers = {}
|
|
10
|
+
) {
|
|
11
|
+
try {
|
|
12
|
+
const path = createTempFolder(name)
|
|
13
|
+
await downloadTarballDirect(url, path, headers)
|
|
14
|
+
|
|
15
|
+
return path
|
|
16
|
+
} catch (e: any) {
|
|
17
|
+
throw new Error(e.message)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -53,7 +53,7 @@ exports.save = async ctx => {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
exports.fetchView = async ctx => {
|
|
56
|
-
// there are no views in external
|
|
56
|
+
// there are no views in external datasources, shouldn't ever be called
|
|
57
57
|
// for now just fetch
|
|
58
58
|
const split = ctx.params.viewName.split("all_")
|
|
59
59
|
ctx.params.tableId = split[1] ? split[1] : split[0]
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
getScreenParams,
|
|
3
|
+
generateScreenID,
|
|
4
|
+
getPluginParams,
|
|
5
|
+
DocumentType,
|
|
6
|
+
} = require("../../db/utils")
|
|
2
7
|
const { AccessController } = require("@budibase/backend-core/roles")
|
|
3
8
|
const { getAppDB } = require("@budibase/backend-core/context")
|
|
4
9
|
const { events } = require("@budibase/backend-core")
|
|
10
|
+
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
11
|
+
const { updateAppPackage } = require("./application")
|
|
5
12
|
|
|
6
13
|
exports.fetch = async ctx => {
|
|
7
14
|
const db = getAppDB()
|
|
@@ -32,6 +39,48 @@ exports.save = async ctx => {
|
|
|
32
39
|
|
|
33
40
|
const response = await db.put(screen)
|
|
34
41
|
|
|
42
|
+
// Find any custom components being used
|
|
43
|
+
let pluginNames = []
|
|
44
|
+
let pluginAdded = false
|
|
45
|
+
findPlugins(screen.props, pluginNames)
|
|
46
|
+
if (pluginNames.length) {
|
|
47
|
+
const globalDB = getGlobalDB()
|
|
48
|
+
const pluginsResponse = await globalDB.allDocs(
|
|
49
|
+
getPluginParams(null, {
|
|
50
|
+
include_docs: true,
|
|
51
|
+
})
|
|
52
|
+
)
|
|
53
|
+
const requiredPlugins = pluginsResponse.rows
|
|
54
|
+
.map(row => row.doc)
|
|
55
|
+
.filter(plugin => {
|
|
56
|
+
return (
|
|
57
|
+
plugin.schema.type === "component" &&
|
|
58
|
+
pluginNames.includes(`plugin/${plugin.name}`)
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Update the app metadata
|
|
63
|
+
const application = await db.get(DocumentType.APP_METADATA)
|
|
64
|
+
let usedPlugins = application.usedPlugins || []
|
|
65
|
+
|
|
66
|
+
requiredPlugins.forEach(plugin => {
|
|
67
|
+
if (!usedPlugins.find(x => x._id === plugin._id)) {
|
|
68
|
+
pluginAdded = true
|
|
69
|
+
usedPlugins.push({
|
|
70
|
+
_id: plugin._id,
|
|
71
|
+
name: plugin.name,
|
|
72
|
+
version: plugin.version,
|
|
73
|
+
jsUrl: plugin.jsUrl,
|
|
74
|
+
hash: plugin.hash,
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
if (pluginAdded) {
|
|
80
|
+
await updateAppPackage({ usedPlugins }, ctx.appId)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
35
84
|
if (eventFn) {
|
|
36
85
|
await eventFn(screen)
|
|
37
86
|
}
|
|
@@ -40,6 +89,7 @@ exports.save = async ctx => {
|
|
|
40
89
|
...screen,
|
|
41
90
|
_id: response.id,
|
|
42
91
|
_rev: response.rev,
|
|
92
|
+
pluginAdded,
|
|
43
93
|
}
|
|
44
94
|
}
|
|
45
95
|
|
|
@@ -56,3 +106,18 @@ exports.destroy = async ctx => {
|
|
|
56
106
|
}
|
|
57
107
|
ctx.status = 200
|
|
58
108
|
}
|
|
109
|
+
|
|
110
|
+
const findPlugins = (component, foundPlugins) => {
|
|
111
|
+
if (!component) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
if (component._component.startsWith("plugin")) {
|
|
115
|
+
if (!foundPlugins.includes(component._component)) {
|
|
116
|
+
foundPlugins.push(component._component)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!component._children || !component._children.length) {
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
component._children.forEach(child => findPlugins(child, foundPlugins))
|
|
123
|
+
}
|
|
@@ -113,6 +113,7 @@ export const serveApp = async function (ctx: any) {
|
|
|
113
113
|
production: env.isProd(),
|
|
114
114
|
appId,
|
|
115
115
|
clientLibPath: clientLibraryPath(appId, appInfo.version, ctx),
|
|
116
|
+
usedPlugins: appInfo.usedPlugins,
|
|
116
117
|
})
|
|
117
118
|
|
|
118
119
|
const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
export let favicon = ""
|
|
4
4
|
|
|
5
5
|
export let clientLibPath
|
|
6
|
+
export let usedPlugins
|
|
6
7
|
</script>
|
|
7
8
|
|
|
8
9
|
<svelte:head>
|
|
@@ -83,6 +84,15 @@
|
|
|
83
84
|
</script>
|
|
84
85
|
<script type="application/javascript" src={clientLibPath}>
|
|
85
86
|
</script>
|
|
87
|
+
<!-- Custom components need inserted after the core client library -->
|
|
88
|
+
<!-- But before loadBudibase is called -->
|
|
89
|
+
{#if usedPlugins?.length}
|
|
90
|
+
{#each usedPlugins as plugin}
|
|
91
|
+
<script
|
|
92
|
+
type="application/javascript"
|
|
93
|
+
src={`/plugins/${plugin.jsUrl}`}></script>
|
|
94
|
+
{/each}
|
|
95
|
+
{/if}
|
|
86
96
|
<script type="application/javascript">
|
|
87
97
|
if (window.loadBudibase) {
|
|
88
98
|
window.loadBudibase()
|
|
@@ -66,7 +66,9 @@
|
|
|
66
66
|
customTheme,
|
|
67
67
|
previewDevice,
|
|
68
68
|
navigation,
|
|
69
|
-
hiddenComponentIds
|
|
69
|
+
hiddenComponentIds,
|
|
70
|
+
usedPlugins,
|
|
71
|
+
location
|
|
70
72
|
} = parsed
|
|
71
73
|
|
|
72
74
|
// Set some flags so the app knows we're in the builder
|
|
@@ -81,6 +83,8 @@
|
|
|
81
83
|
window["##BUDIBASE_PREVIEW_DEVICE##"] = previewDevice
|
|
82
84
|
window["##BUDIBASE_PREVIEW_NAVIGATION##"] = navigation
|
|
83
85
|
window["##BUDIBASE_HIDDEN_COMPONENT_IDS##"] = hiddenComponentIds
|
|
86
|
+
window["##BUDIBASE_USED_PLUGINS##"] = usedPlugins
|
|
87
|
+
window["##BUDIBASE_LOCATION##"] = location
|
|
84
88
|
|
|
85
89
|
// Initialise app
|
|
86
90
|
try {
|
|
@@ -2,16 +2,27 @@ import Router from "@koa/router"
|
|
|
2
2
|
import * as controller from "../controllers/application"
|
|
3
3
|
import authorized from "../../middleware/authorized"
|
|
4
4
|
import { BUILDER } from "@budibase/backend-core/permissions"
|
|
5
|
+
import { applicationValidator } from "./utils/validators"
|
|
5
6
|
|
|
6
7
|
const router = new Router()
|
|
7
8
|
|
|
8
9
|
router
|
|
9
10
|
.post("/api/applications/:appId/sync", authorized(BUILDER), controller.sync)
|
|
10
|
-
.post(
|
|
11
|
+
.post(
|
|
12
|
+
"/api/applications",
|
|
13
|
+
authorized(BUILDER),
|
|
14
|
+
applicationValidator(),
|
|
15
|
+
controller.create
|
|
16
|
+
)
|
|
11
17
|
.get("/api/applications/:appId/definition", controller.fetchAppDefinition)
|
|
12
18
|
.get("/api/applications", controller.fetch)
|
|
13
19
|
.get("/api/applications/:appId/appPackage", controller.fetchAppPackage)
|
|
14
|
-
.put(
|
|
20
|
+
.put(
|
|
21
|
+
"/api/applications/:appId",
|
|
22
|
+
authorized(BUILDER),
|
|
23
|
+
applicationValidator(),
|
|
24
|
+
controller.update
|
|
25
|
+
)
|
|
15
26
|
.post(
|
|
16
27
|
"/api/applications/:appId/client/update",
|
|
17
28
|
authorized(BUILDER),
|
package/src/api/routes/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import metadataRoutes from "./metadata"
|
|
|
24
24
|
import devRoutes from "./dev"
|
|
25
25
|
import cloudRoutes from "./cloud"
|
|
26
26
|
import migrationRoutes from "./migrations"
|
|
27
|
+
import pluginRoutes from "./plugin"
|
|
27
28
|
|
|
28
29
|
export { default as staticRoutes } from "./static"
|
|
29
30
|
export { default as publicRoutes } from "./public"
|
|
@@ -57,4 +58,5 @@ export const mainRoutes = [
|
|
|
57
58
|
tableRoutes,
|
|
58
59
|
rowRoutes,
|
|
59
60
|
migrationRoutes,
|
|
61
|
+
pluginRoutes,
|
|
60
62
|
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Router from "@koa/router"
|
|
2
|
+
import * as controller from "../controllers/plugin"
|
|
3
|
+
import authorized from "../../middleware/authorized"
|
|
4
|
+
import { BUILDER } from "@budibase/backend-core/permissions"
|
|
5
|
+
|
|
6
|
+
const router = new Router()
|
|
7
|
+
|
|
8
|
+
router
|
|
9
|
+
.post("/api/plugin/upload", authorized(BUILDER), controller.upload)
|
|
10
|
+
.post("/api/plugin", authorized(BUILDER), controller.create)
|
|
11
|
+
.get("/api/plugin", authorized(BUILDER), controller.fetch)
|
|
12
|
+
.delete("/api/plugin/:pluginId", authorized(BUILDER), controller.destroy)
|
|
13
|
+
|
|
14
|
+
export default router
|
|
@@ -26,7 +26,7 @@ const read = [],
|
|
|
26
26
|
* responses:
|
|
27
27
|
* 200:
|
|
28
28
|
* description: Returns the created table, including the ID which has been generated for it. This can be
|
|
29
|
-
* internal or external
|
|
29
|
+
* internal or external datasources.
|
|
30
30
|
* content:
|
|
31
31
|
* application/json:
|
|
32
32
|
* schema:
|
package/src/api/routes/table.js
CHANGED
|
@@ -55,7 +55,7 @@ router
|
|
|
55
55
|
* @apiParam (Body) {string} [_rev] If updating an existing internal table then the revision must also be specified.
|
|
56
56
|
* @apiParam (Body) {string} type] This should either be "internal" or "external" depending on the table type -
|
|
57
57
|
* this will default to internal.
|
|
58
|
-
* @apiParam (Body) {string} [sourceId] If creating an external table then this should be set to the
|
|
58
|
+
* @apiParam (Body) {string} [sourceId] If creating an external table then this should be set to the datasource ID. If
|
|
59
59
|
* building an internal table this does not need to be set, although it will be returned as "bb_internal".
|
|
60
60
|
* @apiParam (Body) {string} name The name of the table, this will be used in the UI. To rename the table simply
|
|
61
61
|
* supply the table structure to this endpoint with the name changed.
|
|
@@ -231,20 +231,6 @@ describe("/queries", () => {
|
|
|
231
231
|
url: `/api/queries/preview`,
|
|
232
232
|
})
|
|
233
233
|
})
|
|
234
|
-
|
|
235
|
-
it("should fail with invalid integration type", async () => {
|
|
236
|
-
const { datasource } = await createInvalidIntegration()
|
|
237
|
-
await request
|
|
238
|
-
.post(`/api/queries/preview`)
|
|
239
|
-
.send({
|
|
240
|
-
datasourceId: datasource._id,
|
|
241
|
-
parameters: {},
|
|
242
|
-
fields: {},
|
|
243
|
-
queryVerb: "read",
|
|
244
|
-
})
|
|
245
|
-
.set(config.defaultHeaders())
|
|
246
|
-
.expect(400)
|
|
247
|
-
})
|
|
248
234
|
})
|
|
249
235
|
|
|
250
236
|
describe("execute", () => {
|
|
@@ -261,17 +247,14 @@ describe("/queries", () => {
|
|
|
261
247
|
})
|
|
262
248
|
|
|
263
249
|
it("should fail with invalid integration type", async () => {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
})
|
|
273
|
-
.set(config.defaultHeaders())
|
|
274
|
-
.expect(400)
|
|
250
|
+
let error
|
|
251
|
+
try {
|
|
252
|
+
await createInvalidIntegration()
|
|
253
|
+
} catch (err) {
|
|
254
|
+
error = err
|
|
255
|
+
}
|
|
256
|
+
expect(error).toBeDefined()
|
|
257
|
+
expect(error.message).toBe("No datasource implementation found.")
|
|
275
258
|
})
|
|
276
259
|
})
|
|
277
260
|
|
|
@@ -10,6 +10,7 @@ const Joi = require("joi")
|
|
|
10
10
|
const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("")
|
|
11
11
|
const OPTIONAL_NUMBER = Joi.number().optional().allow(null)
|
|
12
12
|
const OPTIONAL_BOOLEAN = Joi.boolean().optional().allow(null)
|
|
13
|
+
const APP_NAME_REGEX = /^[\w\s]+$/
|
|
13
14
|
|
|
14
15
|
exports.tableValidator = () => {
|
|
15
16
|
// prettier-ignore
|
|
@@ -214,7 +215,7 @@ exports.applicationValidator = () => {
|
|
|
214
215
|
return joiValidator.body(Joi.object({
|
|
215
216
|
_id: OPTIONAL_STRING,
|
|
216
217
|
_rev: OPTIONAL_STRING,
|
|
217
|
-
name: Joi.string().required(),
|
|
218
|
+
name: Joi.string().pattern(new RegExp(APP_NAME_REGEX)).required().error(new Error('App name must be letters, numbers and spaces only')),
|
|
218
219
|
url: OPTIONAL_STRING,
|
|
219
220
|
template: Joi.object({
|
|
220
221
|
templateString: OPTIONAL_STRING,
|
package/src/app.ts
CHANGED
|
@@ -26,10 +26,13 @@ const bullboard = require("./automations/bullboard")
|
|
|
26
26
|
const { logAlert } = require("@budibase/backend-core/logging")
|
|
27
27
|
const { pinoSettings } = require("@budibase/backend-core")
|
|
28
28
|
const { Thread } = require("./threads")
|
|
29
|
+
const fs = require("fs")
|
|
29
30
|
import redis from "./utilities/redis"
|
|
30
31
|
import * as migrations from "./migrations"
|
|
31
32
|
import { events, installation, tenancy } from "@budibase/backend-core"
|
|
32
33
|
import { createAdminUser, getChecklist } from "./utilities/workerRequests"
|
|
34
|
+
import { watch } from "./watch"
|
|
35
|
+
import { initialise as initialiseWebsockets } from "./websocket"
|
|
33
36
|
|
|
34
37
|
const app = new Koa()
|
|
35
38
|
|
|
@@ -74,6 +77,7 @@ if (env.isProd()) {
|
|
|
74
77
|
|
|
75
78
|
const server = http.createServer(app.callback())
|
|
76
79
|
destroyable(server)
|
|
80
|
+
initialiseWebsockets(server)
|
|
77
81
|
|
|
78
82
|
let shuttingDown = false,
|
|
79
83
|
errCode = 0
|
|
@@ -139,6 +143,16 @@ module.exports = server.listen(env.PORT || 0, async () => {
|
|
|
139
143
|
}
|
|
140
144
|
}
|
|
141
145
|
|
|
146
|
+
// monitor plugin directory if required
|
|
147
|
+
if (
|
|
148
|
+
env.SELF_HOSTED &&
|
|
149
|
+
!env.MULTI_TENANCY &&
|
|
150
|
+
env.PLUGINS_DIR &&
|
|
151
|
+
fs.existsSync(env.PLUGINS_DIR)
|
|
152
|
+
) {
|
|
153
|
+
watch()
|
|
154
|
+
}
|
|
155
|
+
|
|
142
156
|
// check for version updates
|
|
143
157
|
await installation.checkInstallVersion()
|
|
144
158
|
|
package/src/db/utils.js
CHANGED
|
@@ -42,6 +42,7 @@ const DocumentType = {
|
|
|
42
42
|
MEM_VIEW: "view",
|
|
43
43
|
USER_FLAG: "flag",
|
|
44
44
|
AUTOMATION_METADATA: "meta_au",
|
|
45
|
+
PLUGIN: "plg",
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
const InternalTables = {
|
|
@@ -370,6 +371,10 @@ exports.getMemoryViewParams = (otherProps = {}) => {
|
|
|
370
371
|
return getDocParams(DocumentType.MEM_VIEW, null, otherProps)
|
|
371
372
|
}
|
|
372
373
|
|
|
374
|
+
exports.generatePluginID = name => {
|
|
375
|
+
return `${DocumentType.PLUGIN}${SEPARATOR}${name}`
|
|
376
|
+
}
|
|
377
|
+
|
|
373
378
|
/**
|
|
374
379
|
* This can be used with the db.allDocs to get a list of IDs
|
|
375
380
|
*/
|
|
@@ -379,3 +384,10 @@ exports.getMultiIDParams = ids => {
|
|
|
379
384
|
include_docs: true,
|
|
380
385
|
}
|
|
381
386
|
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Gets parameters for retrieving automations, this is a utility function for the getDocParams function.
|
|
390
|
+
*/
|
|
391
|
+
exports.getPluginParams = (pluginId = null, otherProps = {}) => {
|
|
392
|
+
return getDocParams(DocumentType.PLUGIN, pluginId, otherProps)
|
|
393
|
+
}
|