@budibase/server 1.3.21 → 1.3.22-alpha.1

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 (310) hide show
  1. package/__mocks__/mongodb.ts +1 -1
  2. package/builder/assets/index.96c69636.js +1008 -0
  3. package/builder/assets/index.c167b5c3.css +6 -0
  4. package/builder/index.html +2 -4
  5. package/coverage/clover.xml +308 -338
  6. package/coverage/coverage-final.json +19 -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/datasource.js.html +73 -34
  13. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/index.html +27 -57
  15. package/coverage/lcov-report/api/controllers/integration.js.html +6 -6
  16. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  21. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/row/external.js.html +2 -2
  25. package/coverage/lcov-report/api/controllers/row/index.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  32. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  34. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  39. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  43. package/coverage/lcov-report/api/index.html +1 -1
  44. package/coverage/lcov-report/api/index.js.html +13 -13
  45. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  46. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  47. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/index.html +1 -1
  56. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/table.js.html +2 -2
  67. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/utils/index.html +9 -9
  70. package/coverage/lcov-report/api/routes/utils/validators.js.html +75 -12
  71. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  73. package/coverage/lcov-report/automations/actions.js.html +1 -1
  74. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  75. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  76. package/coverage/lcov-report/automations/index.html +1 -1
  77. package/coverage/lcov-report/automations/index.js.html +1 -1
  78. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  79. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  80. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/index.html +1 -1
  85. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  95. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  96. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  97. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  104. package/coverage/lcov-report/constants/index.html +1 -1
  105. package/coverage/lcov-report/constants/index.js.html +1 -1
  106. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  107. package/coverage/lcov-report/constants/screens.js.html +1 -1
  108. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  109. package/coverage/lcov-report/db/index.html +14 -14
  110. package/coverage/lcov-report/db/index.js.html +1 -1
  111. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  112. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  113. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  114. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  115. package/coverage/lcov-report/db/newid.js.html +2 -2
  116. package/coverage/lcov-report/db/utils.js.html +30 -18
  117. package/coverage/lcov-report/events/AutomationEmitter.js.html +3 -3
  118. package/coverage/lcov-report/events/index.html +1 -1
  119. package/coverage/lcov-report/events/index.js.html +1 -1
  120. package/coverage/lcov-report/events/utils.js.html +1 -1
  121. package/coverage/lcov-report/index.html +44 -44
  122. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  123. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  124. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  125. package/coverage/lcov-report/middleware/builder.js.html +12 -12
  126. package/coverage/lcov-report/middleware/currentapp.js.html +46 -40
  127. package/coverage/lcov-report/middleware/index.html +15 -15
  128. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  129. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  130. package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
  131. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  132. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  133. package/coverage/lcov-report/utilities/budibaseDir.js.html +3 -3
  134. package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
  135. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  136. package/coverage/lcov-report/utilities/global.js.html +16 -16
  137. package/coverage/lcov-report/utilities/index.html +15 -15
  138. package/coverage/lcov-report/utilities/index.js.html +24 -24
  139. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  140. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  141. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  142. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  143. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  144. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  145. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  146. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  147. package/coverage/lcov-report/utilities/security.js.html +2 -2
  148. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  149. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  150. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  151. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  152. package/coverage/lcov-report/utilities/users.js.html +1 -1
  153. package/coverage/lcov-report/utilities/workerRequests.js.html +32 -8
  154. package/coverage/lcov.info +521 -558
  155. package/dist/api/controllers/application.js +5 -5
  156. package/dist/api/controllers/auth.js +9 -0
  157. package/dist/api/controllers/component.js +19 -6
  158. package/dist/api/controllers/datasource.js +21 -8
  159. package/dist/api/controllers/deploy/index.js +1 -8
  160. package/dist/api/controllers/integration.js +4 -4
  161. package/dist/{migrations/functions/usageQuotas/syncDevelopers.js → api/controllers/plugin/file.js} +13 -13
  162. package/dist/api/controllers/plugin/github.js +69 -0
  163. package/dist/api/controllers/plugin/index.js +144 -0
  164. package/dist/api/controllers/plugin/npm.js +58 -0
  165. package/dist/api/controllers/plugin/uploaders.js +11 -0
  166. package/dist/{migrations/functions/usageQuotas/syncPublishedApps.js → api/controllers/plugin/url.js} +13 -15
  167. package/dist/api/controllers/plugin/utils.js +26 -0
  168. package/dist/api/controllers/row/external.js +1 -1
  169. package/dist/api/controllers/screen.js +62 -14
  170. package/dist/api/controllers/static/index.js +1 -0
  171. package/dist/api/controllers/static/templates/BudibaseApp.svelte +10 -0
  172. package/dist/api/controllers/static/templates/preview.hbs +5 -1
  173. package/dist/api/index.js +1 -1
  174. package/dist/api/routes/application.js +3 -2
  175. package/dist/api/routes/index.js +2 -0
  176. package/dist/{migrations/functions/publishedAppsQuota.js → api/routes/plugin.js} +13 -21
  177. package/dist/api/routes/public/rows.js +1 -82
  178. package/dist/api/routes/public/tables.js +1 -1
  179. package/dist/api/routes/table.js +1 -1
  180. package/dist/api/routes/utils/validators.js +20 -2
  181. package/dist/app.js +16 -1
  182. package/dist/db/utils.js +3 -0
  183. package/dist/environment.js +1 -0
  184. package/dist/integrations/airtable.js +126 -129
  185. package/dist/integrations/arangodb.js +86 -89
  186. package/dist/integrations/base/query.js +2 -2
  187. package/dist/integrations/base/sqlTable.js +3 -1
  188. package/dist/integrations/couchdb.js +80 -83
  189. package/dist/integrations/dynamodb.js +161 -164
  190. package/dist/integrations/elasticsearch.js +135 -138
  191. package/dist/integrations/firebase.js +154 -157
  192. package/dist/integrations/googlesheets.js +323 -327
  193. package/dist/integrations/index.js +99 -51
  194. package/dist/integrations/microsoftSqlServer.js +240 -243
  195. package/dist/integrations/mongodb.js +239 -242
  196. package/dist/integrations/mysql.js +215 -219
  197. package/dist/integrations/oracle.js +318 -322
  198. package/dist/integrations/postgres.js +262 -265
  199. package/dist/integrations/redis.js +134 -139
  200. package/dist/integrations/rest.js +289 -292
  201. package/dist/integrations/s3.js +61 -64
  202. package/dist/integrations/snowflake.js +83 -86
  203. package/dist/middleware/currentapp.js +2 -0
  204. package/dist/migrations/functions/backfill/global.js +0 -3
  205. package/dist/migrations/index.js +0 -10
  206. package/dist/package.json +9 -6
  207. package/dist/tests/utilities/TestConfiguration.js +1 -1
  208. package/dist/threads/query.js +2 -2
  209. package/dist/tsconfig.build.tsbuildinfo +1 -1
  210. package/dist/utilities/fileSystem/index.js +105 -1
  211. package/dist/utilities/workerRequests.js +4 -0
  212. package/dist/watch.js +77 -0
  213. package/dist/websocket.js +22 -0
  214. package/package.json +10 -7
  215. package/scripts/dev/manage.js +4 -0
  216. package/scripts/localdomain.js +3 -1
  217. package/specs/openapi.json +115 -112
  218. package/specs/openapi.yaml +96 -94
  219. package/specs/resources/misc.js +116 -0
  220. package/specs/resources/query.js +1 -1
  221. package/src/api/controllers/application.ts +1 -2
  222. package/src/api/controllers/auth.js +11 -0
  223. package/src/api/controllers/component.ts +57 -0
  224. package/src/api/controllers/datasource.js +21 -8
  225. package/src/api/controllers/deploy/index.ts +1 -6
  226. package/src/api/controllers/integration.js +4 -4
  227. package/src/api/controllers/plugin/file.ts +15 -0
  228. package/src/api/controllers/plugin/github.ts +75 -0
  229. package/src/api/controllers/plugin/index.ts +134 -0
  230. package/src/api/controllers/plugin/npm.ts +56 -0
  231. package/src/api/controllers/plugin/uploaders.ts +4 -0
  232. package/src/api/controllers/plugin/url.ts +12 -0
  233. package/src/api/controllers/plugin/utils.ts +19 -0
  234. package/src/api/controllers/public/mapping/types.ts +8 -0
  235. package/src/api/controllers/row/external.js +1 -1
  236. package/src/api/controllers/screen.ts +122 -0
  237. package/src/api/controllers/static/index.ts +1 -1
  238. package/src/api/controllers/static/templates/BudibaseApp.svelte +10 -0
  239. package/src/api/controllers/static/templates/preview.hbs +5 -1
  240. package/src/api/index.js +1 -1
  241. package/src/api/routes/application.ts +13 -2
  242. package/src/api/routes/index.ts +2 -0
  243. package/src/api/routes/plugin.ts +14 -0
  244. package/src/api/routes/public/rows.ts +1 -82
  245. package/src/api/routes/public/tables.ts +1 -1
  246. package/src/api/routes/table.js +1 -1
  247. package/src/api/routes/tests/query.spec.js +8 -25
  248. package/src/api/routes/tests/user.spec.js +0 -2
  249. package/src/api/routes/utils/validators.js +26 -5
  250. package/src/app.ts +25 -2
  251. package/src/db/utils.js +4 -0
  252. package/src/definitions/openapi.ts +56 -55
  253. package/src/environment.js +1 -0
  254. package/src/integrations/airtable.ts +116 -118
  255. package/src/integrations/arangodb.ts +87 -89
  256. package/src/integrations/base/query.ts +2 -2
  257. package/src/integrations/base/sqlTable.ts +3 -1
  258. package/src/integrations/couchdb.ts +83 -89
  259. package/src/integrations/dynamodb.ts +173 -175
  260. package/src/integrations/elasticsearch.ts +120 -122
  261. package/src/integrations/firebase.ts +157 -159
  262. package/src/integrations/googlesheets.ts +328 -338
  263. package/src/integrations/index.ts +64 -21
  264. package/src/integrations/microsoftSqlServer.ts +249 -251
  265. package/src/integrations/mongodb.ts +261 -258
  266. package/src/integrations/mysql.ts +229 -234
  267. package/src/integrations/oracle.ts +373 -380
  268. package/src/integrations/postgres.ts +264 -268
  269. package/src/integrations/redis.ts +128 -132
  270. package/src/integrations/rest.ts +324 -329
  271. package/src/integrations/s3.ts +68 -71
  272. package/src/integrations/snowflake.ts +80 -82
  273. package/src/integrations/tests/{airtable.spec.js → airtable.spec.ts} +21 -18
  274. package/src/integrations/tests/{arangodb.spec.js → arangodb.spec.ts} +12 -9
  275. package/src/integrations/tests/{couchdb.spec.js → couchdb.spec.ts} +33 -27
  276. package/src/integrations/tests/{dynamodb.spec.js → dynamodb.spec.ts} +45 -41
  277. package/src/integrations/tests/{elasticsearch.spec.js → elasticsearch.spec.ts} +22 -21
  278. package/src/integrations/tests/{firebase.spec.js → firebase.spec.ts} +33 -28
  279. package/src/integrations/tests/{microsoftSqlServer.spec.js → microsoftSqlServer.spec.ts} +12 -11
  280. package/src/integrations/tests/{mongo.spec.js → mongo.spec.ts} +46 -35
  281. package/src/integrations/tests/{mysql.spec.js → mysql.spec.ts} +17 -15
  282. package/src/integrations/tests/{oracle.spec.js → oracle.spec.ts} +19 -17
  283. package/src/integrations/tests/{postgres.spec.js → postgres.spec.ts} +19 -17
  284. package/src/integrations/tests/{redis.spec.js → redis.spec.ts} +27 -18
  285. package/src/integrations/tests/{rest.spec.js → rest.spec.ts} +22 -14
  286. package/src/integrations/tests/{s3.spec.js → s3.spec.ts} +10 -8
  287. package/src/integrations/tests/{sql.spec.js → sql.spec.ts} +228 -177
  288. package/src/middleware/currentapp.js +2 -0
  289. package/src/migrations/functions/backfill/global.ts +0 -3
  290. package/src/migrations/index.ts +0 -16
  291. package/src/module.d.ts +2 -0
  292. package/src/tests/utilities/TestConfiguration.js +1 -1
  293. package/src/threads/query.ts +2 -2
  294. package/src/utilities/fileSystem/index.js +123 -0
  295. package/src/utilities/workerRequests.js +8 -0
  296. package/src/watch.ts +38 -0
  297. package/src/websocket.ts +26 -0
  298. package/builder/assets/index.8d12d461.css +0 -6
  299. package/builder/assets/index.d354271c.js +0 -879
  300. package/builder/assets/vendor.5e1fe644.css +0 -1
  301. package/builder/assets/vendor.67dbd8fa.js +0 -248
  302. package/coverage/lcov-report/api/controllers/component.js.html +0 -199
  303. package/coverage/lcov-report/api/controllers/screen.js.html +0 -259
  304. package/dist/migrations/functions/developerQuota.js +0 -49
  305. package/src/api/controllers/component.js +0 -38
  306. package/src/api/controllers/screen.js +0 -58
  307. package/src/migrations/functions/developerQuota.ts +0 -15
  308. package/src/migrations/functions/publishedAppsQuota.ts +0 -13
  309. package/src/migrations/functions/usageQuotas/syncDevelopers.ts +0 -19
  310. package/src/migrations/functions/usageQuotas/syncPublishedApps.ts +0 -21
@@ -0,0 +1,134 @@
1
+ import { npmUpload, urlUpload, githubUpload, fileUpload } from "./uploaders"
2
+ import { getGlobalDB } from "@budibase/backend-core/tenancy"
3
+ import { validate } from "@budibase/backend-core/plugins"
4
+ import { PluginType, FileType, PluginSource } from "@budibase/types"
5
+ import env from "../../../environment"
6
+ import { ClientAppSocket } from "../../../websocket"
7
+ import { db as dbCore } from "@budibase/backend-core"
8
+ import { plugins } from "@budibase/pro"
9
+
10
+ export async function getPlugins(type?: PluginType) {
11
+ const db = getGlobalDB()
12
+ const response = await db.allDocs(
13
+ dbCore.getPluginParams(null, {
14
+ include_docs: true,
15
+ })
16
+ )
17
+ const plugins = response.rows.map((row: any) => row.doc)
18
+ if (type) {
19
+ return plugins.filter((plugin: any) => plugin.schema?.type === type)
20
+ } else {
21
+ return plugins
22
+ }
23
+ }
24
+
25
+ export async function upload(ctx: any) {
26
+ const plugins: FileType[] =
27
+ ctx.request.files.file.length > 1
28
+ ? Array.from(ctx.request.files.file)
29
+ : [ctx.request.files.file]
30
+ try {
31
+ let docs = []
32
+ // can do single or multiple plugins
33
+ for (let plugin of plugins) {
34
+ const doc = await processUploadedPlugin(plugin, PluginSource.FILE)
35
+ docs.push(doc)
36
+ }
37
+ ctx.body = {
38
+ message: "Plugin(s) uploaded successfully",
39
+ plugins: docs,
40
+ }
41
+ } catch (err: any) {
42
+ const errMsg = err?.message ? err?.message : err
43
+
44
+ ctx.throw(400, `Failed to import plugin: ${errMsg}`)
45
+ }
46
+ }
47
+
48
+ export async function create(ctx: any) {
49
+ const { source, url, headers, githubToken } = ctx.request.body
50
+
51
+ try {
52
+ let metadata
53
+ let directory
54
+ // Generating random name as a backup and needed for url
55
+ let name = "PLUGIN_" + Math.floor(100000 + Math.random() * 900000)
56
+
57
+ switch (source) {
58
+ case PluginSource.NPM:
59
+ const { metadata: metadataNpm, directory: directoryNpm } =
60
+ await npmUpload(url, name)
61
+ metadata = metadataNpm
62
+ directory = directoryNpm
63
+ break
64
+ case PluginSource.GITHUB:
65
+ const { metadata: metadataGithub, directory: directoryGithub } =
66
+ await githubUpload(url, name, githubToken)
67
+ metadata = metadataGithub
68
+ directory = directoryGithub
69
+ break
70
+ case PluginSource.URL:
71
+ const headersObj = headers || {}
72
+ const { metadata: metadataUrl, directory: directoryUrl } =
73
+ await urlUpload(url, name, headersObj)
74
+ metadata = metadataUrl
75
+ directory = directoryUrl
76
+ break
77
+ }
78
+
79
+ validate(metadata?.schema)
80
+
81
+ // Only allow components in cloud
82
+ if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
83
+ throw new Error(
84
+ "Only component plugins are supported outside of self-host"
85
+ )
86
+ }
87
+
88
+ const doc = await plugins.storePlugin(metadata, directory, source)
89
+
90
+ ClientAppSocket.emit("plugins-update", { name, hash: doc.hash })
91
+ ctx.body = {
92
+ message: "Plugin uploaded successfully",
93
+ plugins: [doc],
94
+ }
95
+ ctx.body = { plugin: doc }
96
+ } catch (err: any) {
97
+ const errMsg = err?.message ? err?.message : err
98
+
99
+ ctx.throw(400, `Failed to import plugin: ${errMsg}`)
100
+ }
101
+ }
102
+
103
+ export async function fetch(ctx: any) {
104
+ ctx.body = await getPlugins()
105
+ }
106
+
107
+ export async function destroy(ctx: any) {
108
+ const { pluginId } = ctx.params
109
+
110
+ try {
111
+ await plugins.deletePlugin(pluginId)
112
+
113
+ ctx.body = { message: `Plugin ${ctx.params.pluginId} deleted.` }
114
+ } catch (err: any) {
115
+ ctx.throw(400, err.message)
116
+ }
117
+ }
118
+
119
+ export async function processUploadedPlugin(
120
+ plugin: FileType,
121
+ source?: PluginSource
122
+ ) {
123
+ const { metadata, directory } = await fileUpload(plugin)
124
+ validate(metadata?.schema)
125
+
126
+ // Only allow components in cloud
127
+ if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
128
+ throw new Error("Only component plugins are supported outside of self-host")
129
+ }
130
+
131
+ const doc = await plugins.storePlugin(metadata, directory, source)
132
+ ClientAppSocket.emit("plugins-update", { name: doc.name, hash: doc.hash })
133
+ return doc
134
+ }
@@ -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]
@@ -0,0 +1,122 @@
1
+ import { getScreenParams, generateScreenID, DocumentType } from "../../db/utils"
2
+ import {
3
+ events,
4
+ context,
5
+ tenancy,
6
+ db as dbCore,
7
+ roles,
8
+ } from "@budibase/backend-core"
9
+ import { updateAppPackage } from "./application"
10
+ import { Plugin, ScreenProps } from "@budibase/types"
11
+
12
+ exports.fetch = async (ctx: any) => {
13
+ const db = context.getAppDB()
14
+
15
+ const screens = (
16
+ await db.allDocs(
17
+ getScreenParams(null, {
18
+ include_docs: true,
19
+ })
20
+ )
21
+ ).rows.map((el: any) => el.doc)
22
+
23
+ ctx.body = await new roles.AccessController().checkScreensAccess(
24
+ screens,
25
+ ctx.user.role._id
26
+ )
27
+ }
28
+
29
+ exports.save = async (ctx: any) => {
30
+ const db = context.getAppDB()
31
+ let screen = ctx.request.body
32
+
33
+ let eventFn
34
+ if (!screen._id) {
35
+ screen._id = generateScreenID()
36
+ eventFn = events.screen.created
37
+ }
38
+
39
+ const response = await db.put(screen)
40
+
41
+ // Find any custom components being used
42
+ let pluginNames: string[] = []
43
+ let pluginAdded = false
44
+ findPlugins(screen.props, pluginNames)
45
+ if (pluginNames.length) {
46
+ const globalDB = tenancy.getGlobalDB()
47
+ const pluginsResponse = await globalDB.allDocs(
48
+ dbCore.getPluginParams(null, {
49
+ include_docs: true,
50
+ })
51
+ )
52
+ const requiredPlugins = pluginsResponse.rows
53
+ .map((row: any) => row.doc)
54
+ .filter((plugin: Plugin) => {
55
+ return (
56
+ plugin.schema.type === "component" &&
57
+ pluginNames.includes(`plugin/${plugin.name}`)
58
+ )
59
+ })
60
+
61
+ // Update the app metadata
62
+ const application = await db.get(DocumentType.APP_METADATA)
63
+ let usedPlugins = application.usedPlugins || []
64
+
65
+ requiredPlugins.forEach((plugin: Plugin) => {
66
+ if (!usedPlugins.find((x: Plugin) => x._id === plugin._id)) {
67
+ pluginAdded = true
68
+ usedPlugins.push({
69
+ _id: plugin._id,
70
+ name: plugin.name,
71
+ version: plugin.version,
72
+ jsUrl: plugin.jsUrl,
73
+ hash: plugin.hash,
74
+ })
75
+ }
76
+ })
77
+
78
+ if (pluginAdded) {
79
+ await updateAppPackage({ usedPlugins }, ctx.appId)
80
+ }
81
+ }
82
+
83
+ if (eventFn) {
84
+ await eventFn(screen)
85
+ }
86
+ ctx.message = `Screen ${screen.name} saved.`
87
+ ctx.body = {
88
+ ...screen,
89
+ _id: response.id,
90
+ _rev: response.rev,
91
+ pluginAdded,
92
+ }
93
+ }
94
+
95
+ exports.destroy = async (ctx: any) => {
96
+ const db = context.getAppDB()
97
+ const id = ctx.params.screenId
98
+ const screen = await db.get(id)
99
+
100
+ await db.remove(id, ctx.params.screenRev)
101
+
102
+ await events.screen.deleted(screen)
103
+ ctx.body = {
104
+ message: "Screen deleted successfully",
105
+ }
106
+ ctx.status = 200
107
+ }
108
+
109
+ const findPlugins = (component: ScreenProps, foundPlugins: string[]) => {
110
+ if (!component) {
111
+ return
112
+ }
113
+ if (component._component.startsWith("plugin")) {
114
+ if (!foundPlugins.includes(component._component)) {
115
+ foundPlugins.push(component._component)
116
+ }
117
+ }
118
+ if (!component._children || !component._children.length) {
119
+ return
120
+ }
121
+ component._children.forEach(child => findPlugins(child, foundPlugins))
122
+ }
@@ -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.
@@ -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
- const { query, datasource } = await createInvalidIntegration()
265
- await request
266
- .post(`/api/queries/${query._id}`)
267
- .send({
268
- datasourceId: datasource._id,
269
- parameters: {},
270
- fields: {},
271
- queryVerb: "read",
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