@budibase/server 1.0.218 → 1.0.219-alpha.2

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 (257) hide show
  1. package/__mocks__/node-fetch.ts +9 -0
  2. package/builder/assets/index.00d6b4be.js +977 -0
  3. package/builder/assets/index.7786f497.css +6 -0
  4. package/builder/assets/{vendor.9bf2fcb4.js → vendor.001dcf8c.js} +163 -163
  5. package/builder/index.html +3 -3
  6. package/coverage/clover.xml +868 -794
  7. package/coverage/coverage-final.json +26 -26
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/automation.js.html +111 -12
  11. package/coverage/lcov-report/api/controllers/backup.js.html +9 -6
  12. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/datasource.js.html +16 -16
  15. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/index.html +21 -21
  17. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  23. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/external.js.html +47 -17
  27. package/coverage/lcov-report/api/controllers/row/index.html +34 -34
  28. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +95 -11
  30. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/utils.js.html +17 -8
  32. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  37. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  46. package/coverage/lcov-report/api/index.html +15 -15
  47. package/coverage/lcov-report/api/index.js.html +22 -13
  48. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/automation.js.html +32 -2
  52. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/index.html +1 -1
  59. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  73. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  76. package/coverage/lcov-report/automations/actions.js.html +1 -1
  77. package/coverage/lcov-report/automations/automationUtils.js.html +57 -12
  78. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  79. package/coverage/lcov-report/automations/index.html +17 -17
  80. package/coverage/lcov-report/automations/index.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/filter.js.html +58 -34
  87. package/coverage/lcov-report/automations/steps/index.html +11 -11
  88. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggers.js.html +4 -4
  107. package/coverage/lcov-report/constants/index.html +1 -1
  108. package/coverage/lcov-report/constants/index.js.html +1 -1
  109. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  110. package/coverage/lcov-report/constants/screens.js.html +1 -1
  111. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  112. package/coverage/lcov-report/db/index.html +14 -14
  113. package/coverage/lcov-report/db/index.js.html +1 -1
  114. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  115. package/coverage/lcov-report/db/linkedRows/index.html +13 -13
  116. package/coverage/lcov-report/db/linkedRows/index.js.html +10 -7
  117. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  118. package/coverage/lcov-report/db/newid.js.html +2 -2
  119. package/coverage/lcov-report/db/utils.js.html +27 -51
  120. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  121. package/coverage/lcov-report/events/index.html +1 -1
  122. package/coverage/lcov-report/events/index.js.html +1 -1
  123. package/coverage/lcov-report/events/utils.js.html +1 -1
  124. package/coverage/lcov-report/index.html +74 -74
  125. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  126. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  127. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  128. package/coverage/lcov-report/middleware/builder.js.html +12 -12
  129. package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
  130. package/coverage/lcov-report/middleware/index.html +1 -1
  131. package/coverage/lcov-report/middleware/joi-validator.js.html +10 -10
  132. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  133. package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
  134. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  135. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  136. package/coverage/lcov-report/threads/automation.js.html +18 -9
  137. package/coverage/lcov-report/threads/index.html +25 -25
  138. package/coverage/lcov-report/threads/query.js.html +283 -76
  139. package/coverage/lcov-report/threads/utils.js.html +4 -4
  140. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  141. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  142. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  143. package/coverage/lcov-report/utilities/global.js.html +14 -14
  144. package/coverage/lcov-report/utilities/index.html +1 -1
  145. package/coverage/lcov-report/utilities/index.js.html +9 -9
  146. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  147. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  148. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  149. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  150. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  151. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  152. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  153. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  154. package/coverage/lcov-report/utilities/security.js.html +2 -2
  155. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  156. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  157. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  158. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  159. package/coverage/lcov-report/utilities/users.js.html +1 -1
  160. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  161. package/coverage/lcov.info +1553 -1425
  162. package/dist/api/controllers/application.js +18 -15
  163. package/dist/api/controllers/automation.js +28 -2
  164. package/dist/api/controllers/backup.js +3 -2
  165. package/dist/api/controllers/query/index.js +25 -0
  166. package/dist/api/controllers/row/external.js +19 -7
  167. package/dist/api/controllers/row/internalSearch.js +22 -1
  168. package/dist/api/controllers/row/utils.js +3 -0
  169. package/dist/api/index.js +4 -1
  170. package/dist/api/routes/automation.js +2 -0
  171. package/dist/automations/automationUtils.js +16 -4
  172. package/dist/automations/logging/index.js +70 -0
  173. package/dist/automations/steps/filter.js +38 -29
  174. package/dist/automations/triggers.js +1 -1
  175. package/dist/db/linkedRows/index.js +1 -0
  176. package/dist/db/utils.js +4 -31
  177. package/dist/definitions/datasource.js +1 -0
  178. package/dist/environment.js +1 -0
  179. package/dist/integrations/airtable.js +1 -0
  180. package/dist/integrations/arangodb.js +1 -0
  181. package/dist/integrations/base/sql.js +20 -3
  182. package/dist/integrations/couchdb.js +1 -0
  183. package/dist/integrations/dynamodb.js +1 -0
  184. package/dist/integrations/elasticsearch.js +1 -0
  185. package/dist/integrations/firebase.js +1 -0
  186. package/dist/integrations/googlesheets.js +1 -0
  187. package/dist/integrations/index.js +4 -0
  188. package/dist/integrations/microsoftSqlServer.js +2 -1
  189. package/dist/integrations/mongodb.js +1 -0
  190. package/dist/integrations/mysql.js +2 -1
  191. package/dist/integrations/oracle.js +1 -0
  192. package/dist/integrations/postgres.js +2 -1
  193. package/dist/integrations/queries/sql.js +3 -0
  194. package/dist/integrations/redis.js +1 -0
  195. package/dist/integrations/rest.js +2 -1
  196. package/dist/integrations/s3.js +1 -0
  197. package/dist/integrations/snowflake.js +102 -0
  198. package/dist/package.json +7 -6
  199. package/dist/tests/utilities/TestConfiguration.js +19 -6
  200. package/dist/threads/automation.js +6 -3
  201. package/dist/threads/index.js +15 -1
  202. package/dist/threads/query.js +54 -8
  203. package/dist/tsconfig.build.tsbuildinfo +1 -1
  204. package/dist/utilities/fileSystem/index.js +16 -6
  205. package/package.json +8 -7
  206. package/scripts/integrations/oracle/instantclient/linux/arm64/basiclite-19.10.zip +0 -0
  207. package/scripts/integrations/oracle/instantclient/linux/arm64/install.sh +23 -0
  208. package/scripts/integrations/oracle/instantclient/linux/install.sh +10 -0
  209. package/src/api/controllers/application.ts +18 -14
  210. package/src/api/controllers/automation.js +35 -2
  211. package/src/api/controllers/backup.js +3 -2
  212. package/src/api/controllers/query/index.ts +29 -1
  213. package/src/api/controllers/row/external.js +19 -9
  214. package/src/api/controllers/row/internalSearch.js +28 -0
  215. package/src/api/controllers/row/utils.js +3 -0
  216. package/src/api/index.js +4 -1
  217. package/src/api/routes/automation.js +10 -0
  218. package/src/api/routes/tests/query.spec.js +166 -0
  219. package/src/automations/automationUtils.js +19 -4
  220. package/src/automations/logging/index.ts +35 -0
  221. package/src/automations/steps/filter.js +36 -28
  222. package/src/automations/tests/filter.spec.js +2 -1
  223. package/src/automations/triggers.js +1 -1
  224. package/src/db/linkedRows/index.js +1 -0
  225. package/src/db/utils.js +5 -13
  226. package/src/definitions/common.ts +1 -0
  227. package/src/definitions/datasource.ts +2 -0
  228. package/src/environment.js +1 -0
  229. package/src/integrations/airtable.ts +1 -0
  230. package/src/integrations/arangodb.ts +1 -0
  231. package/src/integrations/base/sql.ts +25 -11
  232. package/src/integrations/couchdb.ts +1 -0
  233. package/src/integrations/dynamodb.ts +1 -0
  234. package/src/integrations/elasticsearch.ts +1 -0
  235. package/src/integrations/firebase.ts +1 -0
  236. package/src/integrations/googlesheets.ts +1 -0
  237. package/src/integrations/index.ts +4 -0
  238. package/src/integrations/microsoftSqlServer.ts +2 -0
  239. package/src/integrations/mongodb.ts +1 -0
  240. package/src/integrations/mysql.ts +2 -0
  241. package/src/integrations/oracle.ts +1 -0
  242. package/src/integrations/postgres.ts +2 -0
  243. package/src/integrations/queries/sql.ts +3 -1
  244. package/src/integrations/redis.ts +1 -0
  245. package/src/integrations/rest.ts +2 -1
  246. package/src/integrations/s3.ts +1 -0
  247. package/src/integrations/snowflake.ts +99 -0
  248. package/src/integrations/tests/rest.spec.js +16 -1
  249. package/src/migrations/tests/index.spec.ts +18 -2
  250. package/src/module.d.ts +2 -0
  251. package/src/tests/utilities/TestConfiguration.js +22 -3
  252. package/src/threads/automation.js +6 -3
  253. package/src/threads/index.ts +5 -1
  254. package/src/threads/query.js +79 -10
  255. package/src/utilities/fileSystem/index.js +22 -8
  256. package/builder/assets/index.24307ca0.css +0 -6
  257. package/builder/assets/index.36419068.js +0 -1316
@@ -33,7 +33,8 @@ const { getTenantId, isMultiTenant } = require("@budibase/backend-core/tenancy")
33
33
  const user_1 = require("./user");
34
34
  const { app: appCache } = require("@budibase/backend-core/cache");
35
35
  const utils_2 = require("../../automations/utils");
36
- const { getAppDB, getProdAppDB, updateAppId, } = require("@budibase/backend-core/context");
36
+ const logging_1 = require("../../automations/logging");
37
+ const { getAppDB, getProdAppDB, updateAppId, doInAppContext, } = require("@budibase/backend-core/context");
37
38
  const rows_1 = require("../../utilities/usageQuota/rows");
38
39
  const pro_1 = require("@budibase/pro");
39
40
  const backend_core_1 = require("@budibase/backend-core");
@@ -159,7 +160,7 @@ const fetch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
159
160
  }
160
161
  }
161
162
  }
162
- ctx.body = apps;
163
+ ctx.body = yield (0, logging_1.checkAppMetadata)(apps);
163
164
  });
164
165
  exports.fetch = fetch;
165
166
  const fetchAppDefinition = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
@@ -486,19 +487,21 @@ const sync = (ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
486
487
  });
487
488
  exports.sync = sync;
488
489
  const updateAppPackage = (appPackage, appId) => __awaiter(void 0, void 0, void 0, function* () {
489
- const db = getAppDB();
490
- const application = yield db.get(utils_1.DocumentTypes.APP_METADATA);
491
- const newAppPackage = Object.assign(Object.assign({}, application), appPackage);
492
- if (appPackage._rev !== application._rev) {
493
- newAppPackage._rev = application._rev;
494
- }
495
- // the locked by property is attached by server but generated from
496
- // Redis, shouldn't ever store it
497
- delete newAppPackage.lockedBy;
498
- yield db.put(newAppPackage);
499
- // remove any cached metadata, so that it will be updated
500
- yield appCache.invalidateAppMetadata(appId);
501
- return newAppPackage;
490
+ return doInAppContext(appId, () => __awaiter(void 0, void 0, void 0, function* () {
491
+ const db = getAppDB();
492
+ const application = yield db.get(utils_1.DocumentTypes.APP_METADATA);
493
+ const newAppPackage = Object.assign(Object.assign({}, application), appPackage);
494
+ if (appPackage._rev !== application._rev) {
495
+ newAppPackage._rev = application._rev;
496
+ }
497
+ // the locked by property is attached by server but generated from
498
+ // Redis, shouldn't ever store it
499
+ delete newAppPackage.lockedBy;
500
+ yield db.put(newAppPackage);
501
+ // remove any cached metadata, so that it will be updated
502
+ yield appCache.invalidateAppMetadata(appId);
503
+ return newAppPackage;
504
+ }));
502
505
  });
503
506
  const createEmptyAppPackage = (ctx, app) => __awaiter(void 0, void 0, void 0, function* () {
504
507
  const db = getAppDB();
@@ -10,13 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  const actions = require("../../automations/actions");
12
12
  const triggers = require("../../automations/triggers");
13
- const { getAutomationParams, generateAutomationID } = require("../../db/utils");
13
+ const { getAutomationParams, generateAutomationID, DocumentTypes, } = require("../../db/utils");
14
14
  const { checkForWebhooks, updateTestHistory, removeDeprecated, } = require("../../automations/utils");
15
15
  const { deleteEntityMetadata } = require("../../utilities");
16
16
  const { MetadataTypes } = require("../../constants");
17
17
  const { setTestFlag, clearTestFlag } = require("../../utilities/redis");
18
- const { getAppDB } = require("@budibase/backend-core/context");
18
+ const { getAppDB, getProdAppDB, doInAppContext, } = require("@budibase/backend-core/context");
19
19
  const { events } = require("@budibase/backend-core");
20
+ const { app } = require("@budibase/backend-core/cache");
21
+ const { automations } = require("@budibase/pro");
20
22
  const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS);
21
23
  const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS);
22
24
  /*************************
@@ -162,6 +164,30 @@ exports.destroy = function (ctx) {
162
164
  yield events.automation.deleted(oldAutomation);
163
165
  });
164
166
  };
167
+ exports.logSearch = function (ctx) {
168
+ return __awaiter(this, void 0, void 0, function* () {
169
+ ctx.body = yield automations.logs.logSearch(ctx.request.body);
170
+ });
171
+ };
172
+ exports.clearLogError = function (ctx) {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ const { automationId, appId } = ctx.request.body;
175
+ yield doInAppContext(appId, () => __awaiter(this, void 0, void 0, function* () {
176
+ const db = getProdAppDB();
177
+ const metadata = yield db.get(DocumentTypes.APP_METADATA);
178
+ if (!automationId) {
179
+ delete metadata.automationErrors;
180
+ }
181
+ else if (metadata.automationErrors &&
182
+ metadata.automationErrors[automationId]) {
183
+ delete metadata.automationErrors[automationId];
184
+ }
185
+ yield db.put(metadata);
186
+ yield app.invalidateAppMetadata(metadata.appId, metadata);
187
+ ctx.body = { message: `Error logs cleared.` };
188
+ }));
189
+ });
190
+ };
165
191
  exports.getActionList = function (ctx) {
166
192
  return __awaiter(this, void 0, void 0, function* () {
167
193
  ctx.body = ACTION_DEFS;
@@ -13,11 +13,12 @@ const { events, context } = require("@budibase/backend-core");
13
13
  const { DocumentTypes } = require("../../db/utils");
14
14
  exports.exportAppDump = function (ctx) {
15
15
  return __awaiter(this, void 0, void 0, function* () {
16
- const { appId } = ctx.query;
16
+ let { appId, excludeRows } = ctx.query;
17
17
  const appName = decodeURI(ctx.query.appname);
18
+ excludeRows = excludeRows === "true";
18
19
  const backupIdentifier = `${appName}-export-${new Date().getTime()}.txt`;
19
20
  ctx.attachment(backupIdentifier);
20
- ctx.body = yield streamBackup(appId);
21
+ ctx.body = yield streamBackup(appId, excludeRows);
21
22
  yield context.doInAppContext(appId, () => __awaiter(this, void 0, void 0, function* () {
22
23
  const appDb = context.getAppDB();
23
24
  const app = yield appDb.get(DocumentTypes.APP_METADATA);
@@ -20,6 +20,8 @@ const environment_1 = require("../../../environment");
20
20
  const context_1 = require("@budibase/backend-core/context");
21
21
  const pro_1 = require("@budibase/pro");
22
22
  const backend_core_1 = require("@budibase/backend-core");
23
+ const utils_3 = require("@budibase/backend-core/utils");
24
+ const constants_2 = require("@budibase/backend-core/constants");
23
25
  const Runner = new threads_1.Thread(threads_1.ThreadType.QUERY, {
24
26
  timeoutMs: environment_1.QUERY_THREAD_TIMEOUT || 10000,
25
27
  });
@@ -111,6 +113,19 @@ function find(ctx) {
111
113
  });
112
114
  }
113
115
  exports.find = find;
116
+ //Required to discern between OIDC OAuth config entries
117
+ function getOAuthConfigCookieId(ctx) {
118
+ if (ctx.user.providerType === constants_2.Configs.OIDC) {
119
+ return (0, utils_3.getCookie)(ctx, constants_2.Cookies.OIDC_CONFIG);
120
+ }
121
+ }
122
+ function getAuthConfig(ctx) {
123
+ const authCookie = (0, utils_3.getCookie)(ctx, constants_2.Cookies.Auth);
124
+ let authConfigCtx = {};
125
+ authConfigCtx["configId"] = getOAuthConfigCookieId(ctx);
126
+ authConfigCtx["sessionId"] = authCookie ? authCookie.sessionId : null;
127
+ return authConfigCtx;
128
+ }
114
129
  function preview(ctx) {
115
130
  return __awaiter(this, void 0, void 0, function* () {
116
131
  const db = (0, context_1.getAppDB)();
@@ -119,6 +134,7 @@ function preview(ctx) {
119
134
  // preview may not have a queryId as it hasn't been saved, but if it does
120
135
  // this stops dynamic variables from calling the same query
121
136
  const { fields, parameters, queryVerb, transformer, queryId } = query;
137
+ const authConfigCtx = getAuthConfig(ctx);
122
138
  try {
123
139
  const runFn = () => Runner.run({
124
140
  appId: ctx.appId,
@@ -128,6 +144,10 @@ function preview(ctx) {
128
144
  parameters,
129
145
  transformer,
130
146
  queryId,
147
+ ctx: {
148
+ user: ctx.user,
149
+ auth: Object.assign({}, authConfigCtx),
150
+ },
131
151
  });
132
152
  const { rows, keys, info, extra } = yield pro_1.quotas.addQuery(runFn);
133
153
  yield backend_core_1.events.query.previewed(datasource, query);
@@ -149,6 +169,7 @@ function execute(ctx, opts = { rowsOnly: false }) {
149
169
  const db = (0, context_1.getAppDB)();
150
170
  const query = yield db.get(ctx.params.queryId);
151
171
  const datasource = yield db.get(query.datasourceId);
172
+ const authConfigCtx = getAuthConfig(ctx);
152
173
  const enrichedParameters = ctx.request.body.parameters || {};
153
174
  // make sure parameters are fully enriched with defaults
154
175
  if (query && query.parameters) {
@@ -169,6 +190,10 @@ function execute(ctx, opts = { rowsOnly: false }) {
169
190
  parameters: enrichedParameters,
170
191
  transformer: query.transformer,
171
192
  queryId: ctx.params.queryId,
193
+ ctx: {
194
+ user: ctx.user,
195
+ auth: Object.assign({}, authConfigCtx),
196
+ },
172
197
  });
173
198
  const { rows, pagination, extra } = yield pro_1.quotas.addQuery(runFn);
174
199
  if (opts && opts.rowsOnly) {
@@ -155,29 +155,41 @@ exports.validate = () => __awaiter(void 0, void 0, void 0, function* () {
155
155
  return { valid: true };
156
156
  });
157
157
  exports.exportRows = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
158
- const { datasourceId, tableName } = breakExternalTableId(ctx.params.tableId);
158
+ const { datasourceId } = breakExternalTableId(ctx.params.tableId);
159
159
  const db = getAppDB();
160
- let format = ctx.query.format;
160
+ const format = ctx.query.format;
161
+ const { columns } = ctx.request.body;
161
162
  const datasource = yield db.get(datasourceId);
162
163
  if (!datasource || !datasource.entities) {
163
164
  ctx.throw(400, "Datasource has not been configured for plus API.");
164
165
  }
165
- const tables = datasource.entities;
166
- const table = tables[tableName];
167
166
  ctx.request.body = {
168
167
  query: {
169
168
  oneOf: {
170
- [table.primaryDisplay]: ctx.request.body.rows.map(id => breakRowIdField(id)[0]),
169
+ _id: ctx.request.body.rows.map(row => JSON.parse(decodeURI(row))[0]),
171
170
  },
172
171
  },
173
172
  };
174
173
  let result = yield exports.search(ctx);
175
- let headers = Object.keys(result.rows[0]);
174
+ let rows = [];
175
+ // Filter data to only specified columns if required
176
+ if (columns && columns.length) {
177
+ for (let i = 0; i < result.rows.length; i++) {
178
+ rows[i] = {};
179
+ for (let column of columns) {
180
+ rows[i][column] = result.rows[i][column];
181
+ }
182
+ }
183
+ }
184
+ else {
185
+ rows = result.rows;
186
+ }
187
+ let headers = Object.keys(rows[0]);
176
188
  const exporter = exporters[format];
177
189
  const filename = `export.${format}`;
178
190
  // send down the file
179
191
  ctx.attachment(filename);
180
- return apiFileReturn(exporter(headers, result.rows));
192
+ return apiFileReturn(exporter(headers, rows));
181
193
  });
182
194
  exports.fetchEnrichedRow = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
183
195
  const id = ctx.params.rowId;
@@ -18,7 +18,7 @@ const { getAppId } = require("@budibase/backend-core/context");
18
18
  */
19
19
  class QueryBuilder {
20
20
  constructor(base) {
21
- this.query = Object.assign({ string: {}, fuzzy: {}, range: {}, equal: {}, notEqual: {}, empty: {}, notEmpty: {} }, base);
21
+ this.query = Object.assign({ string: {}, fuzzy: {}, range: {}, equal: {}, notEqual: {}, empty: {}, notEmpty: {}, oneOf: {} }, base);
22
22
  this.limit = 50;
23
23
  this.sortOrder = "ascending";
24
24
  this.sortType = "string";
@@ -96,6 +96,10 @@ class QueryBuilder {
96
96
  this.query.notEmpty[key] = value;
97
97
  return this;
98
98
  }
99
+ addOneOf(key, value) {
100
+ this.query.oneOf[key] = value;
101
+ return this;
102
+ }
99
103
  /**
100
104
  * Preprocesses a value before going into a lucene search.
101
105
  * Transforms strings to lowercase and wraps strings and bools in quotes.
@@ -201,6 +205,23 @@ class QueryBuilder {
201
205
  if (this.query.notEmpty) {
202
206
  build(this.query.notEmpty, key => `${key}:["" TO *]`);
203
207
  }
208
+ if (this.query.oneOf) {
209
+ build(this.query.oneOf, (key, value) => {
210
+ if (!Array.isArray(value)) {
211
+ if (typeof value === "string") {
212
+ value = value.split(",");
213
+ }
214
+ else {
215
+ return "";
216
+ }
217
+ }
218
+ let orStatement = `${builder.preprocess(value[0], allPreProcessingOpts)}`;
219
+ for (let i = 1; i < value.length; i++) {
220
+ orStatement += ` OR ${builder.preprocess(value[i], allPreProcessingOpts)}`;
221
+ }
222
+ return `${key}:(${orStatement})`;
223
+ });
224
+ }
204
225
  return query;
205
226
  }
206
227
  buildSearchBody() {
@@ -70,6 +70,9 @@ exports.validate = ({ tableId, row, table }) => __awaiter(void 0, void 0, void 0
70
70
  // Validate.js doesn't seem to handle array
71
71
  if (type === FieldTypes.ARRAY && row[fieldName]) {
72
72
  if (row[fieldName].length) {
73
+ if (!Array.isArray(row[fieldName])) {
74
+ row[fieldName] = row[fieldName].split(",");
75
+ }
73
76
  row[fieldName].map(val => {
74
77
  if (!constraints.inclusion.includes(val) &&
75
78
  constraints.inclusion.length !== 0) {
package/dist/api/index.js CHANGED
@@ -69,7 +69,10 @@ router.use((ctx, next) => __awaiter(void 0, void 0, void 0, function* () {
69
69
  error,
70
70
  };
71
71
  ctx.log.error(err);
72
- console.trace(err);
72
+ // unauthorised errors don't provide a useful trace
73
+ if (!env.isTest()) {
74
+ console.trace(err);
75
+ }
73
76
  }
74
77
  }));
75
78
  // authenticated routes
@@ -15,6 +15,8 @@ router
15
15
  .get("/api/automations/:id", paramResource("id"), authorized(BUILDER), controller.find)
16
16
  .put("/api/automations", bodyResource("_id"), authorized(BUILDER), automationValidator(true), controller.update)
17
17
  .post("/api/automations", authorized(BUILDER), automationValidator(false), controller.create)
18
+ .post("/api/automations/logs/search", authorized(BUILDER), controller.logSearch)
19
+ .delete("/api/automations/logs", authorized(BUILDER), controller.clearLogError)
18
20
  .delete("/api/automations/:id/:rev", paramResource("id"), authorized(BUILDER), controller.destroy)
19
21
  .post("/api/automations/:id/trigger", appInfoMiddleware({ appType: AppType.PROD }), paramResource("id"), authorized(PermissionTypes.AUTOMATION, PermissionLevels.EXECUTE), controller.trigger)
20
22
  .post("/api/automations/:id/test", appInfoMiddleware({ appType: AppType.DEV }), paramResource("id"), authorized(PermissionTypes.AUTOMATION, PermissionLevels.EXECUTE), controller.test);
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  const { getTable } = require("../api/controllers/table/utils");
12
- const { findHBSBlocks } = require("@budibase/string-templates");
12
+ const { findHBSBlocks, decodeJSBinding, isJSBinding, encodeJSBinding, } = require("@budibase/string-templates");
13
13
  /**
14
14
  * When values are input to the system generally they will be of type string as this is required for template strings.
15
15
  * This can generate some odd scenarios as the Schema of the automation requires a number but the builder might supply
@@ -81,11 +81,23 @@ exports.getError = err => {
81
81
  return typeof err !== "string" ? err.toString() : err;
82
82
  };
83
83
  exports.substituteLoopStep = (hbsString, substitute) => {
84
- let blocks = findHBSBlocks(hbsString);
84
+ let blocks = [];
85
+ let checkForJS = isJSBinding(hbsString);
86
+ if (checkForJS) {
87
+ hbsString = decodeJSBinding(hbsString);
88
+ blocks.push(hbsString);
89
+ }
90
+ else {
91
+ blocks = findHBSBlocks(hbsString);
92
+ }
85
93
  for (let block of blocks) {
86
- let oldBlock = block;
87
94
  block = block.replace(/loop/, substitute);
88
- hbsString = hbsString.replace(new RegExp(oldBlock, "g"), block);
95
+ if (checkForJS) {
96
+ hbsString = encodeJSBinding(block);
97
+ }
98
+ else {
99
+ hbsString = block;
100
+ }
89
101
  }
90
102
  return hbsString;
91
103
  };
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.checkAppMetadata = exports.storeLog = void 0;
36
+ const env = __importStar(require("../../environment"));
37
+ const pro_1 = require("@budibase/pro");
38
+ const backend_core_1 = require("@budibase/backend-core");
39
+ function storeLog(automation, results) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ // can disable this if un-needed in self-host, also only do this for prod apps
42
+ if (env.DISABLE_AUTOMATION_LOGS) {
43
+ return;
44
+ }
45
+ yield pro_1.automations.logs.storeLog(automation, results);
46
+ });
47
+ }
48
+ exports.storeLog = storeLog;
49
+ function checkAppMetadata(apps) {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ const maxStartDate = yield pro_1.automations.logs.oldestLogDate();
52
+ for (let metadata of apps) {
53
+ if (!metadata.automationErrors) {
54
+ continue;
55
+ }
56
+ for (let [key, errors] of Object.entries(metadata.automationErrors)) {
57
+ const updated = [];
58
+ for (let error of errors) {
59
+ const startDate = error.split(backend_core_1.db.SEPARATOR)[2];
60
+ if (startDate > maxStartDate) {
61
+ updated.push(error);
62
+ }
63
+ }
64
+ metadata.automationErrors[key] = updated;
65
+ }
66
+ }
67
+ return apps;
68
+ });
69
+ }
70
+ exports.checkAppMetadata = checkAppMetadata;
@@ -56,46 +56,55 @@ exports.definition = {
56
56
  outputs: {
57
57
  properties: {
58
58
  success: {
59
+ type: "boolean",
60
+ description: "Whether the action was successful",
61
+ },
62
+ result: {
59
63
  type: "boolean",
60
64
  description: "Whether the logic block passed",
61
65
  },
62
66
  },
63
- required: ["success"],
67
+ required: ["success", "result"],
64
68
  },
65
69
  },
66
70
  };
67
71
  exports.run = function filter({ inputs }) {
68
72
  return __awaiter(this, void 0, void 0, function* () {
69
- let { field, condition, value } = inputs;
70
- // coerce types so that we can use them
71
- if (!isNaN(value) && !isNaN(field)) {
72
- value = parseFloat(value);
73
- field = parseFloat(field);
74
- }
75
- else if (!isNaN(Date.parse(value)) && !isNaN(Date.parse(field))) {
76
- value = Date.parse(value);
77
- field = Date.parse(field);
78
- }
79
- let success = false;
80
- if (typeof field !== "object" && typeof value !== "object") {
81
- switch (condition) {
82
- case FilterConditions.EQUAL:
83
- success = field === value;
84
- break;
85
- case FilterConditions.NOT_EQUAL:
86
- success = field !== value;
87
- break;
88
- case FilterConditions.GREATER_THAN:
89
- success = field > value;
90
- break;
91
- case FilterConditions.LESS_THAN:
92
- success = field < value;
93
- break;
73
+ try {
74
+ let { field, condition, value } = inputs;
75
+ // coerce types so that we can use them
76
+ if (!isNaN(value) && !isNaN(field)) {
77
+ value = parseFloat(value);
78
+ field = parseFloat(field);
79
+ }
80
+ else if (!isNaN(Date.parse(value)) && !isNaN(Date.parse(field))) {
81
+ value = Date.parse(value);
82
+ field = Date.parse(field);
83
+ }
84
+ let result = false;
85
+ if (typeof field !== "object" && typeof value !== "object") {
86
+ switch (condition) {
87
+ case FilterConditions.EQUAL:
88
+ result = field === value;
89
+ break;
90
+ case FilterConditions.NOT_EQUAL:
91
+ result = field !== value;
92
+ break;
93
+ case FilterConditions.GREATER_THAN:
94
+ result = field > value;
95
+ break;
96
+ case FilterConditions.LESS_THAN:
97
+ result = field < value;
98
+ break;
99
+ }
100
+ }
101
+ else {
102
+ result = false;
94
103
  }
104
+ return { success: true, result };
95
105
  }
96
- else {
97
- success = false;
106
+ catch (err) {
107
+ return { success: false, result: false };
98
108
  }
99
- return { success };
100
109
  });
101
110
  };
@@ -95,7 +95,7 @@ exports.externalTrigger = function (automation, params, { getResponses } = {}) {
95
95
  // values are likely to be submitted as strings, so we shall convert to correct type
96
96
  const coercedFields = {};
97
97
  const fields = automation.definition.trigger.inputs.fields;
98
- for (let key of Object.keys(fields)) {
98
+ for (let key of Object.keys(fields || {})) {
99
99
  coercedFields[key] = coerce(params.fields[key], fields[key]);
100
100
  }
101
101
  params.fields = coercedFields;
@@ -56,6 +56,7 @@ function getLinksForRows(rows) {
56
56
  // have to get unique as the previous table query can
57
57
  // return duplicates, could be querying for both tables in a relation
58
58
  return getUniqueByProp(responses
59
+ .filter(el => el != null)
59
60
  // create a unique ID which we can use for getting only unique ones
60
61
  .map(el => (Object.assign(Object.assign({}, el), { unique: el.id + el.thisId + el.fieldName }))), "unique");
61
62
  });
package/dist/db/utils.js CHANGED
@@ -1,39 +1,13 @@
1
1
  "use strict";
2
2
  const newid = require("./newid");
3
- const { DocumentTypes: CoreDocTypes, getRoleParams, generateRoleID, APP_DEV_PREFIX, APP_PREFIX, SEPARATOR, StaticDatabases, isDevAppID, isProdAppID, getDevelopmentAppID, generateAppID, } = require("@budibase/backend-core/db");
3
+ const { DocumentTypes: CoreDocTypes, getRoleParams, generateRoleID, APP_DEV_PREFIX, APP_PREFIX, SEPARATOR, StaticDatabases, isDevAppID, isProdAppID, getDevelopmentAppID, generateAppID, getQueryIndex, ViewNames, } = require("@budibase/backend-core/db");
4
4
  const UNICODE_MAX = "\ufff0";
5
5
  const AppStatus = {
6
6
  DEV: "development",
7
7
  ALL: "all",
8
8
  DEPLOYED: "published",
9
9
  };
10
- const DocumentTypes = {
11
- APP: CoreDocTypes.APP,
12
- DEV: CoreDocTypes.DEV,
13
- APP_DEV: CoreDocTypes.APP_DEV,
14
- APP_METADATA: CoreDocTypes.APP_METADATA,
15
- ROLE: CoreDocTypes.ROLE,
16
- TABLE: "ta",
17
- ROW: "ro",
18
- USER: "us",
19
- AUTOMATION: "au",
20
- LINK: "li",
21
- WEBHOOK: "wh",
22
- INSTANCE: "inst",
23
- LAYOUT: "layout",
24
- SCREEN: "screen",
25
- DATASOURCE: "datasource",
26
- DATASOURCE_PLUS: "datasource_plus",
27
- QUERY: "query",
28
- DEPLOYMENTS: "deployments",
29
- METADATA: "metadata",
30
- MEM_VIEW: "view",
31
- USER_FLAG: "flag",
32
- };
33
- const ViewNames = {
34
- LINK: "by_link",
35
- ROUTING: "screen_routes",
36
- };
10
+ const DocumentTypes = Object.assign(Object.assign({}, CoreDocTypes), { TABLE: "ta", ROW: "ro", USER: "us", AUTOMATION: "au", LINK: "li", WEBHOOK: "wh", INSTANCE: "inst", LAYOUT: "layout", SCREEN: "screen", DATASOURCE: "datasource", DATASOURCE_PLUS: "datasource_plus", QUERY: "query", DEPLOYMENTS: "deployments", METADATA: "metadata", MEM_VIEW: "view", USER_FLAG: "flag" });
37
11
  const InternalTables = {
38
12
  USER_METADATA: "ta_users",
39
13
  };
@@ -54,6 +28,7 @@ exports.isDevAppID = isDevAppID;
54
28
  exports.isProdAppID = isProdAppID;
55
29
  exports.USER_METDATA_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`;
56
30
  exports.LINK_USER_METADATA_PREFIX = `${DocumentTypes.LINK}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`;
31
+ exports.TABLE_ROW_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${DocumentTypes.TABLE}`;
57
32
  exports.ViewNames = ViewNames;
58
33
  exports.InternalTables = InternalTables;
59
34
  exports.DocumentTypes = DocumentTypes;
@@ -66,9 +41,7 @@ exports.generateAppID = generateAppID;
66
41
  exports.generateDevAppID = getDevelopmentAppID;
67
42
  exports.generateRoleID = generateRoleID;
68
43
  exports.getRoleParams = getRoleParams;
69
- exports.getQueryIndex = viewName => {
70
- return `database/${viewName}`;
71
- };
44
+ exports.getQueryIndex = getQueryIndex;
72
45
  /**
73
46
  * If creating DB allDocs/query params with only a single top level ID this can be used, this
74
47
  * is usually the case as most of our docs are top level e.g. tables, automations, users and so on.
@@ -52,6 +52,7 @@ var SourceNames;
52
52
  SourceNames["GOOGLE_SHEETS"] = "GOOGLE_SHEETS";
53
53
  SourceNames["FIRESTORE"] = "FIRESTORE";
54
54
  SourceNames["REDIS"] = "REDIS";
55
+ SourceNames["SNOWFLAKE"] = "SNOWFLAKE";
55
56
  })(SourceNames = exports.SourceNames || (exports.SourceNames = {}));
56
57
  var IncludeRelationships;
57
58
  (function (IncludeRelationships) {
@@ -66,6 +66,7 @@ module.exports = {
66
66
  ALLOW_DEV_AUTOMATIONS: process.env.ALLOW_DEV_AUTOMATIONS,
67
67
  DISABLE_THREADING: process.env.DISABLE_THREADING,
68
68
  DISABLE_DEVELOPER_LICENSE: process.env.DISABLE_DEVELOPER_LICENSE,
69
+ DISABLE_AUTOMATION_LOGS: process.env.DISABLE_AUTOMATION_LOGS,
69
70
  MULTI_TENANCY: process.env.MULTI_TENANCY,
70
71
  ENABLE_ANALYTICS: process.env.ENABLE_ANALYTICS,
71
72
  SELF_HOSTED: process.env.SELF_HOSTED,
@@ -17,6 +17,7 @@ var AirtableModule;
17
17
  docs: "https://airtable.com/api",
18
18
  description: "Airtable is a spreadsheet-database hybrid, with the features of a database but applied to a spreadsheet.",
19
19
  friendlyName: "Airtable",
20
+ type: "Spreadsheet",
20
21
  datasource: {
21
22
  apiKey: {
22
23
  type: datasource_1.DatasourceFieldTypes.PASSWORD,
@@ -16,6 +16,7 @@ var ArangoModule;
16
16
  const SCHEMA = {
17
17
  docs: "https://github.com/arangodb/arangojs",
18
18
  friendlyName: "ArangoDB",
19
+ type: "Non-relational",
19
20
  description: "ArangoDB is a scalable open-source multi-model database natively supporting graph, document and search. All supported data models & access patterns can be combined in queries allowing for maximal flexibility. ",
20
21
  datasource: {
21
22
  url: {