@budibase/server 1.3.20 → 1.3.21-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.
Files changed (308) hide show
  1. package/__mocks__/mongodb.ts +1 -1
  2. package/builder/assets/index.75653b72.js +1005 -0
  3. package/builder/assets/index.f1b70f52.css +6 -0
  4. package/builder/index.html +2 -4
  5. package/coverage/clover.xml +451 -390
  6. package/coverage/coverage-final.json +21 -21
  7. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/auth.js.html +41 -8
  9. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/component.js.html +68 -11
  13. package/coverage/lcov-report/api/controllers/datasource.js.html +73 -34
  14. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/index.html +46 -46
  16. package/coverage/lcov-report/api/controllers/integration.js.html +6 -6
  17. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  22. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/row/external.js.html +2 -2
  26. package/coverage/lcov-report/api/controllers/row/index.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/screen.js.html +207 -12
  32. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  36. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  45. package/coverage/lcov-report/api/index.html +1 -1
  46. package/coverage/lcov-report/api/index.js.html +13 -13
  47. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/index.html +1 -1
  58. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/table.js.html +2 -2
  69. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/utils/index.html +9 -9
  72. package/coverage/lcov-report/api/routes/utils/validators.js.html +75 -12
  73. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  75. package/coverage/lcov-report/automations/actions.js.html +1 -1
  76. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  77. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  78. package/coverage/lcov-report/automations/index.html +1 -1
  79. package/coverage/lcov-report/automations/index.js.html +1 -1
  80. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/index.html +1 -1
  87. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  97. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  106. package/coverage/lcov-report/constants/index.html +1 -1
  107. package/coverage/lcov-report/constants/index.js.html +1 -1
  108. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  109. package/coverage/lcov-report/constants/screens.js.html +1 -1
  110. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  111. package/coverage/lcov-report/db/index.html +18 -18
  112. package/coverage/lcov-report/db/index.js.html +1 -1
  113. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  114. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  115. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  116. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  117. package/coverage/lcov-report/db/newid.js.html +2 -2
  118. package/coverage/lcov-report/db/utils.js.html +56 -20
  119. package/coverage/lcov-report/events/AutomationEmitter.js.html +3 -3
  120. package/coverage/lcov-report/events/index.html +1 -1
  121. package/coverage/lcov-report/events/index.js.html +1 -1
  122. package/coverage/lcov-report/events/utils.js.html +1 -1
  123. package/coverage/lcov-report/index.html +46 -46
  124. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  125. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  126. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  127. package/coverage/lcov-report/middleware/builder.js.html +12 -12
  128. package/coverage/lcov-report/middleware/currentapp.js.html +46 -40
  129. package/coverage/lcov-report/middleware/index.html +15 -15
  130. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  131. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  132. package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
  133. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  134. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  135. package/coverage/lcov-report/utilities/budibaseDir.js.html +3 -3
  136. package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
  137. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  138. package/coverage/lcov-report/utilities/global.js.html +16 -16
  139. package/coverage/lcov-report/utilities/index.html +15 -15
  140. package/coverage/lcov-report/utilities/index.js.html +24 -24
  141. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  142. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  143. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  144. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  145. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  146. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  147. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  148. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  149. package/coverage/lcov-report/utilities/security.js.html +2 -2
  150. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  151. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  152. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  153. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  154. package/coverage/lcov-report/utilities/users.js.html +1 -1
  155. package/coverage/lcov-report/utilities/workerRequests.js.html +32 -8
  156. package/coverage/lcov.info +798 -672
  157. package/dist/api/controllers/application.js +5 -5
  158. package/dist/api/controllers/auth.js +9 -0
  159. package/dist/api/controllers/component.js +14 -1
  160. package/dist/api/controllers/datasource.js +21 -8
  161. package/dist/api/controllers/deploy/index.js +1 -8
  162. package/dist/api/controllers/integration.js +4 -4
  163. package/dist/{migrations/functions/usageQuotas/syncDevelopers.js → api/controllers/plugin/file.js} +13 -13
  164. package/dist/api/controllers/plugin/github.js +69 -0
  165. package/dist/api/controllers/plugin/index.js +200 -0
  166. package/dist/api/controllers/plugin/npm.js +58 -0
  167. package/dist/api/controllers/plugin/uploaders.js +11 -0
  168. package/dist/{migrations/functions/usageQuotas/syncPublishedApps.js → api/controllers/plugin/url.js} +13 -15
  169. package/dist/api/controllers/plugin/utils.js +26 -0
  170. package/dist/api/controllers/row/external.js +1 -1
  171. package/dist/api/controllers/screen.js +52 -2
  172. package/dist/api/controllers/static/index.js +1 -0
  173. package/dist/api/controllers/static/templates/BudibaseApp.svelte +10 -0
  174. package/dist/api/controllers/static/templates/preview.hbs +5 -1
  175. package/dist/api/index.js +1 -1
  176. package/dist/api/routes/application.js +3 -2
  177. package/dist/api/routes/index.js +2 -0
  178. package/dist/{migrations/functions/publishedAppsQuota.js → api/routes/plugin.js} +13 -21
  179. package/dist/api/routes/public/rows.js +1 -82
  180. package/dist/api/routes/public/tables.js +1 -1
  181. package/dist/api/routes/table.js +1 -1
  182. package/dist/api/routes/utils/validators.js +20 -2
  183. package/dist/app.js +16 -1
  184. package/dist/db/utils.js +10 -1
  185. package/dist/environment.js +1 -0
  186. package/dist/integrations/airtable.js +126 -129
  187. package/dist/integrations/arangodb.js +86 -89
  188. package/dist/integrations/base/query.js +2 -2
  189. package/dist/integrations/base/sqlTable.js +3 -1
  190. package/dist/integrations/couchdb.js +80 -83
  191. package/dist/integrations/dynamodb.js +161 -164
  192. package/dist/integrations/elasticsearch.js +135 -138
  193. package/dist/integrations/firebase.js +154 -157
  194. package/dist/integrations/googlesheets.js +323 -327
  195. package/dist/integrations/index.js +99 -51
  196. package/dist/integrations/microsoftSqlServer.js +240 -243
  197. package/dist/integrations/mongodb.js +239 -242
  198. package/dist/integrations/mysql.js +215 -219
  199. package/dist/integrations/oracle.js +318 -322
  200. package/dist/integrations/postgres.js +262 -265
  201. package/dist/integrations/redis.js +134 -139
  202. package/dist/integrations/rest.js +289 -292
  203. package/dist/integrations/s3.js +61 -64
  204. package/dist/integrations/snowflake.js +83 -86
  205. package/dist/middleware/currentapp.js +2 -0
  206. package/dist/migrations/functions/backfill/global.js +0 -3
  207. package/dist/migrations/index.js +0 -10
  208. package/dist/package.json +9 -6
  209. package/dist/tests/utilities/TestConfiguration.js +1 -1
  210. package/dist/threads/query.js +2 -2
  211. package/dist/tsconfig.build.tsbuildinfo +1 -1
  212. package/dist/utilities/fileSystem/index.js +111 -1
  213. package/dist/utilities/workerRequests.js +4 -0
  214. package/dist/watch.js +77 -0
  215. package/dist/websocket.js +22 -0
  216. package/package.json +10 -7
  217. package/scripts/dev/manage.js +4 -0
  218. package/scripts/localdomain.js +3 -1
  219. package/specs/openapi.json +115 -112
  220. package/specs/openapi.yaml +96 -94
  221. package/specs/resources/misc.js +116 -0
  222. package/specs/resources/query.js +1 -1
  223. package/src/api/controllers/application.ts +1 -2
  224. package/src/api/controllers/auth.js +11 -0
  225. package/src/api/controllers/component.js +21 -2
  226. package/src/api/controllers/datasource.js +21 -8
  227. package/src/api/controllers/deploy/index.ts +1 -6
  228. package/src/api/controllers/integration.js +4 -4
  229. package/src/api/controllers/plugin/file.ts +15 -0
  230. package/src/api/controllers/plugin/github.ts +75 -0
  231. package/src/api/controllers/plugin/index.ts +215 -0
  232. package/src/api/controllers/plugin/npm.ts +56 -0
  233. package/src/api/controllers/plugin/uploaders.ts +4 -0
  234. package/src/api/controllers/plugin/url.ts +12 -0
  235. package/src/api/controllers/plugin/utils.ts +19 -0
  236. package/src/api/controllers/public/mapping/types.ts +8 -0
  237. package/src/api/controllers/row/external.js +1 -1
  238. package/src/api/controllers/screen.js +66 -1
  239. package/src/api/controllers/static/index.ts +1 -1
  240. package/src/api/controllers/static/templates/BudibaseApp.svelte +10 -0
  241. package/src/api/controllers/static/templates/preview.hbs +5 -1
  242. package/src/api/index.js +1 -1
  243. package/src/api/routes/application.ts +13 -2
  244. package/src/api/routes/index.ts +2 -0
  245. package/src/api/routes/plugin.ts +14 -0
  246. package/src/api/routes/public/rows.ts +1 -82
  247. package/src/api/routes/public/tables.ts +1 -1
  248. package/src/api/routes/table.js +1 -1
  249. package/src/api/routes/tests/query.spec.js +8 -25
  250. package/src/api/routes/tests/user.spec.js +0 -2
  251. package/src/api/routes/utils/validators.js +26 -5
  252. package/src/app.ts +25 -2
  253. package/src/db/utils.js +12 -0
  254. package/src/definitions/openapi.ts +56 -55
  255. package/src/environment.js +1 -0
  256. package/src/integrations/airtable.ts +116 -118
  257. package/src/integrations/arangodb.ts +87 -89
  258. package/src/integrations/base/query.ts +2 -2
  259. package/src/integrations/base/sqlTable.ts +3 -1
  260. package/src/integrations/couchdb.ts +83 -89
  261. package/src/integrations/dynamodb.ts +173 -175
  262. package/src/integrations/elasticsearch.ts +120 -122
  263. package/src/integrations/firebase.ts +157 -159
  264. package/src/integrations/googlesheets.ts +328 -338
  265. package/src/integrations/index.ts +64 -21
  266. package/src/integrations/microsoftSqlServer.ts +249 -251
  267. package/src/integrations/mongodb.ts +261 -258
  268. package/src/integrations/mysql.ts +229 -234
  269. package/src/integrations/oracle.ts +373 -380
  270. package/src/integrations/postgres.ts +264 -268
  271. package/src/integrations/redis.ts +128 -132
  272. package/src/integrations/rest.ts +324 -329
  273. package/src/integrations/s3.ts +68 -71
  274. package/src/integrations/snowflake.ts +80 -82
  275. package/src/integrations/tests/{airtable.spec.js → airtable.spec.ts} +21 -18
  276. package/src/integrations/tests/{arangodb.spec.js → arangodb.spec.ts} +12 -9
  277. package/src/integrations/tests/{couchdb.spec.js → couchdb.spec.ts} +33 -27
  278. package/src/integrations/tests/{dynamodb.spec.js → dynamodb.spec.ts} +45 -41
  279. package/src/integrations/tests/{elasticsearch.spec.js → elasticsearch.spec.ts} +22 -21
  280. package/src/integrations/tests/{firebase.spec.js → firebase.spec.ts} +33 -28
  281. package/src/integrations/tests/{microsoftSqlServer.spec.js → microsoftSqlServer.spec.ts} +12 -11
  282. package/src/integrations/tests/{mongo.spec.js → mongo.spec.ts} +46 -35
  283. package/src/integrations/tests/{mysql.spec.js → mysql.spec.ts} +17 -15
  284. package/src/integrations/tests/{oracle.spec.js → oracle.spec.ts} +19 -17
  285. package/src/integrations/tests/{postgres.spec.js → postgres.spec.ts} +19 -17
  286. package/src/integrations/tests/{redis.spec.js → redis.spec.ts} +27 -18
  287. package/src/integrations/tests/{rest.spec.js → rest.spec.ts} +22 -14
  288. package/src/integrations/tests/{s3.spec.js → s3.spec.ts} +10 -8
  289. package/src/integrations/tests/{sql.spec.js → sql.spec.ts} +228 -177
  290. package/src/middleware/currentapp.js +2 -0
  291. package/src/migrations/functions/backfill/global.ts +0 -3
  292. package/src/migrations/index.ts +0 -16
  293. package/src/module.d.ts +2 -0
  294. package/src/tests/utilities/TestConfiguration.js +1 -1
  295. package/src/threads/query.ts +2 -2
  296. package/src/utilities/fileSystem/index.js +130 -0
  297. package/src/utilities/workerRequests.js +8 -0
  298. package/src/watch.ts +38 -0
  299. package/src/websocket.ts +26 -0
  300. package/builder/assets/index.79165a2a.js +0 -876
  301. package/builder/assets/index.fbe5f97c.css +0 -6
  302. package/builder/assets/vendor.5e1fe644.css +0 -1
  303. package/builder/assets/vendor.67dbd8fa.js +0 -248
  304. package/dist/migrations/functions/developerQuota.js +0 -49
  305. package/src/migrations/functions/developerQuota.ts +0 -15
  306. package/src/migrations/functions/publishedAppsQuota.ts +0 -13
  307. package/src/migrations/functions/usageQuotas/syncDevelopers.ts +0 -19
  308. package/src/migrations/functions/usageQuotas/syncPublishedApps.ts +0 -21
@@ -0,0 +1,215 @@
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, Plugin } from "@budibase/types"
12
+ import env from "../../../environment"
13
+ import { ClientAppSocket } from "../../../websocket"
14
+ import { events } from "@budibase/backend-core"
15
+
16
+ export async function getPlugins(type?: PluginType) {
17
+ const db = getGlobalDB()
18
+ const response = await db.allDocs(
19
+ getPluginParams(null, {
20
+ include_docs: true,
21
+ })
22
+ )
23
+ const plugins = response.rows.map((row: any) => row.doc)
24
+ if (type) {
25
+ return plugins.filter((plugin: any) => plugin.schema?.type === type)
26
+ } else {
27
+ return plugins
28
+ }
29
+ }
30
+
31
+ export async function upload(ctx: any) {
32
+ const plugins: FileType[] =
33
+ ctx.request.files.file.length > 1
34
+ ? Array.from(ctx.request.files.file)
35
+ : [ctx.request.files.file]
36
+ try {
37
+ let docs = []
38
+ // can do single or multiple plugins
39
+ for (let plugin of plugins) {
40
+ const doc = await processPlugin(plugin, PluginSource.FILE)
41
+ docs.push(doc)
42
+ }
43
+ ctx.body = {
44
+ message: "Plugin(s) uploaded successfully",
45
+ plugins: docs,
46
+ }
47
+ } catch (err: any) {
48
+ const errMsg = err?.message ? err?.message : err
49
+
50
+ ctx.throw(400, `Failed to import plugin: ${errMsg}`)
51
+ }
52
+ }
53
+
54
+ export async function create(ctx: any) {
55
+ const { source, url, headers, githubToken } = ctx.request.body
56
+
57
+ try {
58
+ let metadata
59
+ let directory
60
+ // Generating random name as a backup and needed for url
61
+ let name = "PLUGIN_" + Math.floor(100000 + Math.random() * 900000)
62
+
63
+ switch (source) {
64
+ case PluginSource.NPM:
65
+ const { metadata: metadataNpm, directory: directoryNpm } =
66
+ await npmUpload(url, name)
67
+ metadata = metadataNpm
68
+ directory = directoryNpm
69
+ break
70
+ case PluginSource.GITHUB:
71
+ const { metadata: metadataGithub, directory: directoryGithub } =
72
+ await githubUpload(url, name, githubToken)
73
+ metadata = metadataGithub
74
+ directory = directoryGithub
75
+ break
76
+ case PluginSource.URL:
77
+ const headersObj = headers || {}
78
+ const { metadata: metadataUrl, directory: directoryUrl } =
79
+ await urlUpload(url, name, headersObj)
80
+ metadata = metadataUrl
81
+ directory = directoryUrl
82
+ break
83
+ }
84
+
85
+ validate(metadata?.schema)
86
+
87
+ // Only allow components in cloud
88
+ if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
89
+ throw new Error(
90
+ "Only component plugins are supported outside of self-host"
91
+ )
92
+ }
93
+
94
+ const doc = await storePlugin(metadata, directory, source)
95
+
96
+ ctx.body = {
97
+ message: "Plugin uploaded successfully",
98
+ plugins: [doc],
99
+ }
100
+ } catch (err: any) {
101
+ const errMsg = err?.message ? err?.message : err
102
+
103
+ ctx.throw(400, `Failed to import plugin: ${errMsg}`)
104
+ }
105
+ ctx.status = 200
106
+ }
107
+
108
+ export async function fetch(ctx: any) {
109
+ ctx.body = await getPlugins()
110
+ }
111
+
112
+ export async function destroy(ctx: any) {
113
+ const db = getGlobalDB()
114
+ const { pluginId } = ctx.params
115
+
116
+ try {
117
+ const plugin: Plugin = await db.get(pluginId)
118
+ const bucketPath = `${plugin.name}/`
119
+ await deleteFolder(ObjectStoreBuckets.PLUGINS, bucketPath)
120
+
121
+ await db.remove(pluginId, plugin._rev)
122
+ await events.plugin.deleted(plugin)
123
+ } catch (err: any) {
124
+ const errMsg = err?.message ? err?.message : err
125
+
126
+ ctx.throw(400, `Failed to delete plugin: ${errMsg}`)
127
+ }
128
+
129
+ ctx.message = `Plugin ${ctx.params.pluginId} deleted.`
130
+ ctx.status = 200
131
+ }
132
+
133
+ export async function storePlugin(
134
+ metadata: any,
135
+ directory: any,
136
+ source?: PluginSource
137
+ ) {
138
+ const db = getGlobalDB()
139
+ const version = metadata.package.version,
140
+ name = metadata.package.name,
141
+ description = metadata.package.description,
142
+ hash = metadata.schema.hash
143
+
144
+ // first open the tarball into tmp directory
145
+ const bucketPath = `${name}/`
146
+ const files = await uploadDirectory(
147
+ ObjectStoreBuckets.PLUGINS,
148
+ directory,
149
+ bucketPath
150
+ )
151
+ const jsFile = files.find((file: any) => file.name.endsWith(".js"))
152
+ if (!jsFile) {
153
+ throw new Error(`Plugin missing .js file.`)
154
+ }
155
+ // validate the JS for a datasource
156
+ if (metadata.schema.type === PluginType.DATASOURCE) {
157
+ const js = loadJSFile(directory, jsFile.name)
158
+ // TODO: this isn't safe - but we need full node environment
159
+ // in future we should do this in a thread for safety
160
+ try {
161
+ eval(js)
162
+ } catch (err: any) {
163
+ const message = err?.message ? err.message : JSON.stringify(err)
164
+ throw new Error(`JS invalid: ${message}`)
165
+ }
166
+ }
167
+ const jsFileName = jsFile.name
168
+ const pluginId = generatePluginID(name)
169
+
170
+ // overwrite existing docs entirely if they exist
171
+ let rev
172
+ try {
173
+ const existing = await db.get(pluginId)
174
+ rev = existing._rev
175
+ } catch (err) {
176
+ rev = undefined
177
+ }
178
+ let doc: Plugin = {
179
+ _id: pluginId,
180
+ _rev: rev,
181
+ ...metadata,
182
+ name,
183
+ version,
184
+ hash,
185
+ description,
186
+ jsUrl: `${bucketPath}${jsFileName}`,
187
+ }
188
+
189
+ if (source) {
190
+ doc = {
191
+ ...doc,
192
+ source,
193
+ }
194
+ }
195
+
196
+ const response = await db.put(doc)
197
+ await events.plugin.imported(doc)
198
+ ClientAppSocket.emit("plugin-update", { name, hash })
199
+ return {
200
+ ...doc,
201
+ _rev: response.rev,
202
+ }
203
+ }
204
+
205
+ export async function processPlugin(plugin: FileType, source?: PluginSource) {
206
+ const { metadata, directory } = await fileUpload(plugin)
207
+ validate(metadata?.schema)
208
+
209
+ // Only allow components in cloud
210
+ if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
211
+ throw new Error("Only component plugins are supported outside of self-host")
212
+ }
213
+
214
+ return await storePlugin(metadata, directory, source)
215
+ }
@@ -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,4 @@
1
+ export { fileUpload } from "./file"
2
+ export { githubUpload } from "./github"
3
+ export { npmUpload } from "./npm"
4
+ export { urlUpload } from "./url"
@@ -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
+ }
@@ -4,10 +4,18 @@ export type Query = components["schemas"]["query"]
4
4
  export type ExecuteQuery = components["schemas"]["executeQueryOutput"]
5
5
 
6
6
  export type Application = components["schemas"]["applicationOutput"]["data"]
7
+ export type CreateApplicationParams = components["schemas"]["application"]
7
8
 
8
9
  export type Table = components["schemas"]["tableOutput"]["data"]
10
+ export type CreateTableParams = components["schemas"]["table"]
9
11
 
10
12
  export type Row = components["schemas"]["rowOutput"]["data"]
11
13
  export type RowSearch = components["schemas"]["searchOutput"]
14
+ export type CreateRowParams = components["schemas"]["row"]
12
15
 
13
16
  export type User = components["schemas"]["userOutput"]["data"]
17
+ export type CreateUserParams = components["schemas"]["user"]
18
+
19
+ export type SearchInputParams =
20
+ | components["schemas"]["nameSearch"]
21
+ | components["schemas"]["rowSearch"]
@@ -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 data sources, shouldn't ever be called
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 { getScreenParams, generateScreenID } = require("../../db/utils")
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
+ }
@@ -18,7 +18,6 @@ const { DocumentType } = require("../../../db/utils")
18
18
  const { getAppDB, getAppId } = require("@budibase/backend-core/context")
19
19
  const { setCookie, clearCookie } = require("@budibase/backend-core/utils")
20
20
  const AWS = require("aws-sdk")
21
-
22
21
  const fs = require("fs")
23
22
  const {
24
23
  downloadTarballDirect,
@@ -113,6 +112,7 @@ export const serveApp = async function (ctx: any) {
113
112
  production: env.isProd(),
114
113
  appId,
115
114
  clientLibPath: clientLibraryPath(appId, appInfo.version, ctx),
115
+ usedPlugins: appInfo.usedPlugins,
116
116
  })
117
117
 
118
118
  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 {
package/src/api/index.js CHANGED
@@ -54,8 +54,8 @@ router
54
54
  noTenancyRequired: true,
55
55
  })
56
56
  )
57
- .use(currentApp)
58
57
  .use(pro.licensing())
58
+ .use(currentApp)
59
59
  .use(auditLog)
60
60
 
61
61
  // error handling middleware
@@ -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("/api/applications", authorized(BUILDER), controller.create)
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("/api/applications/:appId", authorized(BUILDER), controller.update)
20
+ .put(
21
+ "/api/applications/:appId",
22
+ authorized(BUILDER),
23
+ applicationValidator({ isCreate: false }),
24
+ controller.update
25
+ )
15
26
  .post(
16
27
  "/api/applications/:appId/client/update",
17
28
  authorized(BUILDER),
@@ -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
@@ -143,88 +143,7 @@ read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read))
143
143
  * content:
144
144
  * application/json:
145
145
  * schema:
146
- * type: object
147
- * required:
148
- * - query
149
- * properties:
150
- * query:
151
- * type: object
152
- * properties:
153
- * allOr:
154
- * type: boolean
155
- * description: Specifies that a row should be returned if it satisfies
156
- * any of the specified options, rather than requiring it to fulfill all
157
- * the search parameters. This defaults to false, meaning AND logic will be used.
158
- * string:
159
- * type: object
160
- * example:
161
- * columnName1: value
162
- * columnName2: value
163
- * description: A map of field name to the string to search for,
164
- * this will look for rows that have a value starting with the
165
- * string value.
166
- * additionalProperties:
167
- * type: string
168
- * description: The value to search for in the column.
169
- * fuzzy:
170
- * type: object
171
- * description: A fuzzy search, only supported by internal tables.
172
- * range:
173
- * type: object
174
- * description: Searches within a range, the format of this must be
175
- * in the format of an object with a "low" and "high" property.
176
- * example:
177
- * columnName1: { low: 10, high: 20 }
178
- * equal:
179
- * type: object
180
- * description: Searches for rows that have a column value that is
181
- * exactly the value set.
182
- * notEqual:
183
- * type: object
184
- * description: Searches for any row which does not contain the specified
185
- * column value.
186
- * empty:
187
- * type: object
188
- * description: Searches for rows which do not contain the specified column.
189
- * The object should simply contain keys of the column names, these
190
- * can map to any value.
191
- * example:
192
- * columnName1: ""
193
- * notEmpty:
194
- * type: object
195
- * description: Searches for rows which have the specified column.
196
- * oneOf:
197
- * type: object
198
- * description: Searches for rows which have a column value that is any
199
- * of the specified values. The format of this must be columnName -> [value1, value2].
200
- * paginate:
201
- * type: boolean
202
- * description: Enables pagination, by default this is disabled.
203
- * bookmark:
204
- * oneOf:
205
- * - type: string
206
- * - type: integer
207
- * description: If retrieving another page, the bookmark from the previous request must be supplied.
208
- * limit:
209
- * type: integer
210
- * description: The maximum number of rows to return, useful when paginating, for internal tables this
211
- * will be limited to 1000, for SQL tables it will be 5000.
212
- * sort:
213
- * type: object
214
- * description: A set of parameters describing the sort behaviour of the search.
215
- * properties:
216
- * order:
217
- * type: string
218
- * enum: [ascending, descending]
219
- * description: The order of the sort, by default this is ascending.
220
- * column:
221
- * type: string
222
- * description: The name of the column by which the rows will be sorted.
223
- * type:
224
- * type: string
225
- * enum: [string, number]
226
- * description: Defines whether the column should be treated as a string
227
- * or as numbers when sorting.
146
+ * $ref: '#/components/schemas/rowSearch'
228
147
  * responses:
229
148
  * 200:
230
149
  * description: The response will contain an array of rows that match the search parameters.
@@ -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 data sources.
29
+ * internal or external datasources.
30
30
  * content:
31
31
  * application/json:
32
32
  * schema:
@@ -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 data source ID. If
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.