@budibase/server 1.0.18 → 1.0.19-alpha.3

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 (227) hide show
  1. package/__mocks__/node-fetch.ts +3 -0
  2. package/builder/assets/bb-spaceship.8f6e81e1.svg +227 -0
  3. package/builder/assets/{index.4fb3f887.css → index.540a5506.css} +1 -1
  4. package/builder/assets/{index.3587ba82.js → index.6de3403f.js} +236 -231
  5. package/builder/assets/{vendor.470042a4.js → vendor.a9288856.js} +1 -1
  6. package/builder/index.html +3 -3
  7. package/coverage/clover.xml +440 -372
  8. package/coverage/coverage-final.json +17 -16
  9. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/application.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/datasource.js.html +14 -14
  18. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/index.html +23 -38
  21. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/query/index.html +126 -0
  26. package/coverage/lcov-report/api/controllers/{query.js.html → query/index.js.html} +159 -27
  27. package/coverage/lcov-report/api/controllers/query/validation.js.html +203 -0
  28. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/index.html +1 -1
  32. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +108 -9
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +18 -6
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/index.html +9 -9
  66. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/query.js.html +11 -98
  72. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/user.js.html +32 -2
  81. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  82. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  83. package/coverage/lcov-report/automations/actions.js.html +1 -1
  84. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  85. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  86. package/coverage/lcov-report/automations/index.html +1 -1
  87. package/coverage/lcov-report/automations/index.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/index.html +1 -1
  97. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  99. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  111. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  112. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  113. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  114. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  115. package/coverage/lcov-report/automations/utils.js.html +1 -1
  116. package/coverage/lcov-report/constants/index.html +1 -1
  117. package/coverage/lcov-report/constants/index.js.html +22 -22
  118. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  119. package/coverage/lcov-report/constants/screens.js.html +1 -1
  120. package/coverage/lcov-report/db/client.js.html +18 -18
  121. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  122. package/coverage/lcov-report/db/index.html +15 -15
  123. package/coverage/lcov-report/db/index.js.html +3 -3
  124. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  125. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  126. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  127. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  128. package/coverage/lcov-report/db/newid.js.html +4 -4
  129. package/coverage/lcov-report/db/utils.js.html +91 -64
  130. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  131. package/coverage/lcov-report/events/index.html +1 -1
  132. package/coverage/lcov-report/events/index.js.html +1 -1
  133. package/coverage/lcov-report/events/utils.js.html +1 -1
  134. package/coverage/lcov-report/index.html +67 -52
  135. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  136. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  137. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  138. package/coverage/lcov-report/middleware/authorized.js.html +2 -2
  139. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  140. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  141. package/coverage/lcov-report/middleware/index.html +1 -1
  142. package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
  143. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  144. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  145. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  146. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  147. package/coverage/lcov-report/threads/automation.js.html +1 -1
  148. package/coverage/lcov-report/threads/index.html +20 -20
  149. package/coverage/lcov-report/threads/index.js.html +1 -1
  150. package/coverage/lcov-report/threads/query.js.html +63 -12
  151. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  152. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  153. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  154. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  155. package/coverage/lcov-report/utilities/global.js.html +1 -1
  156. package/coverage/lcov-report/utilities/index.html +19 -19
  157. package/coverage/lcov-report/utilities/index.js.html +66 -33
  158. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
  159. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  160. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  161. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  162. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  164. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  165. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  166. package/coverage/lcov-report/utilities/security.js.html +2 -2
  167. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  168. package/coverage/lcov-report/utilities/users.js.html +1 -1
  169. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  170. package/coverage/lcov.info +688 -583
  171. package/dist/api/controllers/query/import/index.js +79 -0
  172. package/dist/api/controllers/query/import/sources/base/index.js +63 -0
  173. package/dist/api/controllers/query/import/sources/base/openapi.js +42 -0
  174. package/dist/api/controllers/query/import/sources/curl.js +90 -0
  175. package/dist/api/controllers/query/import/sources/openapi2.js +139 -0
  176. package/dist/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  177. package/dist/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  178. package/dist/api/controllers/{query.js → query/index.js} +42 -6
  179. package/dist/api/controllers/query/validation.js +37 -0
  180. package/dist/api/controllers/user.js +37 -1
  181. package/dist/api/controllers/webhook.js +4 -0
  182. package/dist/api/routes/query.js +2 -32
  183. package/dist/api/routes/user.js +3 -1
  184. package/dist/db/utils.js +8 -0
  185. package/dist/definitions/datasource.js +6 -1
  186. package/dist/integrations/rest.js +136 -114
  187. package/dist/package.json +8 -4
  188. package/dist/threads/query.js +14 -2
  189. package/dist/tsconfig.tsbuildinfo +1 -1
  190. package/dist/utilities/index.js +10 -0
  191. package/package.json +9 -5
  192. package/src/api/controllers/query/import/index.ts +85 -0
  193. package/src/api/controllers/query/import/sources/base/index.ts +85 -0
  194. package/src/api/controllers/query/import/sources/base/openapi.ts +24 -0
  195. package/src/api/controllers/query/import/sources/curl.ts +94 -0
  196. package/src/api/controllers/query/import/sources/openapi2.ts +159 -0
  197. package/src/api/controllers/query/import/sources/tests/curl/curl.spec.js +104 -0
  198. package/src/api/controllers/query/import/sources/tests/curl/data/delete.txt +1 -0
  199. package/src/api/controllers/query/import/sources/tests/curl/data/empty-body.txt +2 -0
  200. package/src/api/controllers/query/import/sources/tests/curl/data/get.txt +1 -0
  201. package/src/api/controllers/query/import/sources/tests/curl/data/headers.txt +3 -0
  202. package/src/api/controllers/query/import/sources/tests/curl/data/patch.txt +2 -0
  203. package/src/api/controllers/query/import/sources/tests/curl/data/path.txt +1 -0
  204. package/src/api/controllers/query/import/sources/tests/curl/data/post.txt +2 -0
  205. package/src/api/controllers/query/import/sources/tests/curl/data/put.txt +2 -0
  206. package/src/api/controllers/query/import/sources/tests/curl/data/query.txt +1 -0
  207. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
  208. package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.yaml +160 -0
  209. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
  210. package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.yaml +711 -0
  211. package/src/api/controllers/query/import/sources/tests/openapi2/openapi2.spec.js +239 -0
  212. package/src/api/controllers/query/import/tests/index.spec.js +115 -0
  213. package/src/api/controllers/{query.js → query/index.js} +50 -6
  214. package/src/api/controllers/query/validation.js +41 -0
  215. package/src/api/controllers/user.js +33 -0
  216. package/src/api/controllers/webhook.js +4 -0
  217. package/src/api/routes/query.js +5 -34
  218. package/src/api/routes/user.js +10 -0
  219. package/src/db/utils.js +9 -0
  220. package/src/definitions/common.ts +2 -16
  221. package/src/definitions/datasource.ts +73 -1
  222. package/src/integrations/base/IntegrationBase.ts +4 -4
  223. package/src/integrations/oracle.ts +1 -1
  224. package/src/integrations/rest.ts +145 -134
  225. package/src/integrations/tests/rest.spec.js +71 -7
  226. package/src/threads/query.js +19 -2
  227. package/src/utilities/index.js +11 -0
@@ -1,4 +1,4 @@
1
- import { Row, Table } from "./common"
1
+ import { Row, Table, Base } from "./common"
2
2
 
3
3
  export enum Operation {
4
4
  CREATE = "CREATE",
@@ -181,3 +181,75 @@ export interface SqlQuery {
181
181
  export interface QueryOptions {
182
182
  disableReturning?: boolean
183
183
  }
184
+
185
+ export interface Datasource extends Base {
186
+ type: string
187
+ name: string
188
+ source: SourceNames
189
+ // the config is defined by the schema
190
+ config: {
191
+ [key: string]: string | number | boolean
192
+ }
193
+ plus: boolean
194
+ entities?: {
195
+ [key: string]: Table
196
+ }
197
+ }
198
+
199
+ export enum AuthType {
200
+ BASIC = "basic",
201
+ BEARER = "bearer",
202
+ }
203
+
204
+ interface AuthConfig {
205
+ _id: string
206
+ name: string
207
+ type: AuthType
208
+ config: BasicAuthConfig | BearerAuthConfig
209
+ }
210
+
211
+ export interface BasicAuthConfig {
212
+ username: string
213
+ password: string
214
+ }
215
+
216
+ export interface BearerAuthConfig {
217
+ token: string
218
+ }
219
+
220
+ export interface QueryParameter {
221
+ name: string
222
+ default: string
223
+ }
224
+
225
+ export interface RestQueryFields {
226
+ path: string
227
+ queryString?: string
228
+ headers: { [key: string]: any }
229
+ disabledHeaders: { [key: string]: any }
230
+ requestBody: any
231
+ bodyType: string
232
+ json: object
233
+ method: string
234
+ authConfigId: string
235
+ }
236
+
237
+ export interface RestConfig {
238
+ url: string
239
+ defaultHeaders: {
240
+ [key: string]: any
241
+ }
242
+ authConfigs: AuthConfig[]
243
+ }
244
+
245
+ export interface Query {
246
+ _id?: string
247
+ datasourceId: string
248
+ name: string
249
+ parameters: QueryParameter[]
250
+ fields: RestQueryFields | any
251
+ transformer: string | null
252
+ schema: any
253
+ readable: boolean
254
+ queryVerb: string
255
+ }
@@ -1,6 +1,6 @@
1
1
  export interface IntegrationBase {
2
- create?(query: any): Promise<any[]>
3
- read?(query: any): Promise<any[]>
4
- update?(query: any): Promise<any[]>
5
- delete?(query: any): Promise<any[]>
2
+ create?(query: any): Promise<any[] | any>
3
+ read?(query: any): Promise<any[] | any>
4
+ update?(query: any): Promise<any[] | any>
5
+ delete?(query: any): Promise<any[] | any>
6
6
  }
@@ -450,7 +450,7 @@ module OracleModule {
450
450
  })
451
451
  return lastRow.rows
452
452
  } else {
453
- return [{ [ operation.toLowerCase() ]: true }]
453
+ return [{ [operation.toLowerCase()]: true }]
454
454
  }
455
455
  }
456
456
  }
@@ -2,29 +2,61 @@ import {
2
2
  Integration,
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
+ RestConfig,
6
+ RestQueryFields as RestQuery,
7
+ AuthType,
8
+ BasicAuthConfig,
9
+ BearerAuthConfig
5
10
  } from "../definitions/datasource"
6
11
  import { IntegrationBase } from "./base/IntegrationBase"
7
12
 
13
+ const BodyTypes = {
14
+ NONE: "none",
15
+ FORM_DATA: "form",
16
+ ENCODED: "encoded",
17
+ JSON: "json",
18
+ TEXT: "text",
19
+ }
20
+
21
+ const coreFields = {
22
+ path: {
23
+ type: DatasourceFieldTypes.STRING,
24
+ display: "URL",
25
+ },
26
+ queryString: {
27
+ type: DatasourceFieldTypes.STRING,
28
+ },
29
+ headers: {
30
+ type: DatasourceFieldTypes.OBJECT,
31
+ },
32
+ enabledHeaders: {
33
+ type: DatasourceFieldTypes.OBJECT,
34
+ },
35
+ requestBody: {
36
+ type: DatasourceFieldTypes.JSON,
37
+ },
38
+ bodyType: {
39
+ type: DatasourceFieldTypes.STRING,
40
+ enum: Object.values(BodyTypes),
41
+ },
42
+ }
43
+
8
44
  module RestModule {
9
45
  const fetch = require("node-fetch")
10
-
11
- interface RestConfig {
12
- url: string
13
- defaultHeaders: {
14
- [key: string]: any
15
- }
16
- }
46
+ const { formatBytes } = require("../utilities")
47
+ const { performance } = require("perf_hooks")
17
48
 
18
49
  const SCHEMA: Integration = {
19
50
  docs: "https://github.com/node-fetch/node-fetch",
20
51
  description:
21
- "Representational state transfer (REST) is a de-facto standard for a software architecture for interactive applications that typically use multiple Web services. ",
52
+ "With the REST API datasource, you can connect, query and pull data from multiple REST APIs. You can then use the retrieved data to build apps.",
22
53
  friendlyName: "REST API",
23
54
  datasource: {
24
55
  url: {
25
56
  type: DatasourceFieldTypes.STRING,
26
- default: "localhost",
27
- required: true,
57
+ default: "",
58
+ required: false,
59
+ deprecated: true,
28
60
  },
29
61
  defaultHeaders: {
30
62
  type: DatasourceFieldTypes.OBJECT,
@@ -37,97 +69,30 @@ module RestModule {
37
69
  readable: true,
38
70
  displayName: "POST",
39
71
  type: QueryTypes.FIELDS,
40
- urlDisplay: true,
41
- fields: {
42
- path: {
43
- type: DatasourceFieldTypes.STRING,
44
- },
45
- queryString: {
46
- type: DatasourceFieldTypes.STRING,
47
- },
48
- headers: {
49
- type: DatasourceFieldTypes.OBJECT,
50
- },
51
- requestBody: {
52
- type: DatasourceFieldTypes.JSON,
53
- },
54
- },
72
+ fields: coreFields,
55
73
  },
56
74
  read: {
57
75
  displayName: "GET",
58
76
  readable: true,
59
77
  type: QueryTypes.FIELDS,
60
- urlDisplay: true,
61
- fields: {
62
- path: {
63
- type: DatasourceFieldTypes.STRING,
64
- },
65
- queryString: {
66
- type: DatasourceFieldTypes.STRING,
67
- },
68
- headers: {
69
- type: DatasourceFieldTypes.OBJECT,
70
- },
71
- },
78
+ fields: coreFields,
72
79
  },
73
80
  update: {
74
81
  displayName: "PUT",
75
82
  readable: true,
76
83
  type: QueryTypes.FIELDS,
77
- urlDisplay: true,
78
- fields: {
79
- path: {
80
- type: DatasourceFieldTypes.STRING,
81
- },
82
- queryString: {
83
- type: DatasourceFieldTypes.STRING,
84
- },
85
- headers: {
86
- type: DatasourceFieldTypes.OBJECT,
87
- },
88
- requestBody: {
89
- type: DatasourceFieldTypes.JSON,
90
- },
91
- },
84
+ fields: coreFields,
92
85
  },
93
86
  patch: {
94
87
  displayName: "PATCH",
95
88
  readable: true,
96
89
  type: QueryTypes.FIELDS,
97
- urlDisplay: true,
98
- fields: {
99
- path: {
100
- type: DatasourceFieldTypes.STRING,
101
- },
102
- queryString: {
103
- type: DatasourceFieldTypes.STRING,
104
- },
105
- headers: {
106
- type: DatasourceFieldTypes.OBJECT,
107
- },
108
- requestBody: {
109
- type: DatasourceFieldTypes.JSON,
110
- },
111
- },
90
+ fields: coreFields,
112
91
  },
113
92
  delete: {
114
93
  displayName: "DELETE",
115
94
  type: QueryTypes.FIELDS,
116
- urlDisplay: true,
117
- fields: {
118
- path: {
119
- type: DatasourceFieldTypes.STRING,
120
- },
121
- queryString: {
122
- type: DatasourceFieldTypes.STRING,
123
- },
124
- headers: {
125
- type: DatasourceFieldTypes.OBJECT,
126
- },
127
- requestBody: {
128
- type: DatasourceFieldTypes.JSON,
129
- },
130
- },
95
+ fields: coreFields,
131
96
  },
132
97
  },
133
98
  }
@@ -137,99 +102,145 @@ module RestModule {
137
102
  private headers: {
138
103
  [key: string]: string
139
104
  } = {}
105
+ private startTimeMs: number = performance.now()
140
106
 
141
107
  constructor(config: RestConfig) {
142
108
  this.config = config
143
109
  }
144
110
 
145
111
  async parseResponse(response: any) {
112
+ let data, raw, headers
146
113
  const contentType = response.headers.get("content-type")
147
114
  if (contentType && contentType.indexOf("application/json") !== -1) {
148
- return await response.json()
115
+ data = await response.json()
116
+ raw = JSON.stringify(data)
149
117
  } else {
150
- return await response.text()
118
+ data = await response.text()
119
+ raw = data
120
+ }
121
+ const size = formatBytes(response.headers.get("content-length") || Buffer.byteLength(raw, "utf8"))
122
+ const time = `${Math.round(performance.now() - this.startTimeMs)}ms`
123
+ headers = response.headers.raw()
124
+ for (let [key, value] of Object.entries(headers)) {
125
+ headers[key] = Array.isArray(value) ? value[0] : value
126
+ }
127
+ return {
128
+ data,
129
+ info: {
130
+ code: response.status,
131
+ size,
132
+ time,
133
+ },
134
+ extra: {
135
+ raw,
136
+ headers,
137
+ },
151
138
  }
152
139
  }
153
140
 
154
141
  getUrl(path: string, queryString: string): string {
155
- return `${this.config.url}/${path}?${queryString}`
142
+ const main = `${path}?${queryString}`
143
+ let complete = main
144
+ if (this.config.url && !main.startsWith(this.config.url)) {
145
+ complete = !this.config.url ? main : `${this.config.url}/${main}`
146
+ }
147
+ if (!complete.startsWith("http")) {
148
+ complete = `http://${complete}`
149
+ }
150
+ return complete
156
151
  }
157
152
 
158
- async create({ path = "", queryString = "", headers = {}, json = {} }) {
159
- this.headers = {
160
- ...this.config.defaultHeaders,
161
- ...headers,
153
+ getAuthHeaders(authConfigId: string): { [key: string]: any }{
154
+ let headers: any = {}
155
+
156
+ if (this.config.authConfigs && authConfigId) {
157
+ const authConfig = this.config.authConfigs.filter(
158
+ c => c._id === authConfigId
159
+ )[0]
160
+ // check the config still exists before proceeding
161
+ // if not - do nothing
162
+ if (authConfig) {
163
+ let config
164
+ switch (authConfig.type) {
165
+ case AuthType.BASIC:
166
+ config = authConfig.config as BasicAuthConfig
167
+ headers.Authorization = `Basic ${Buffer.from(
168
+ `${config.username}:${config.password}`
169
+ ).toString("base64")}`
170
+ break
171
+ case AuthType.BEARER:
172
+ config = authConfig.config as BearerAuthConfig
173
+ headers.Authorization = `Bearer ${config.token}`
174
+ break
175
+ }
176
+ }
162
177
  }
163
178
 
164
- const response = await fetch(this.getUrl(path, queryString), {
165
- method: "POST",
166
- headers: this.headers,
167
- body: JSON.stringify(json),
168
- })
169
-
170
- return await this.parseResponse(response)
179
+ return headers
171
180
  }
172
181
 
173
- async read({ path = "", queryString = "", headers = {} }) {
182
+ async _req(query: RestQuery) {
183
+ const { path = "", queryString = "", headers = {}, method = "GET", disabledHeaders, bodyType, requestBody, authConfigId } = query
184
+ const authHeaders = this.getAuthHeaders(authConfigId)
185
+
174
186
  this.headers = {
175
187
  ...this.config.defaultHeaders,
176
188
  ...headers,
189
+ ...authHeaders,
177
190
  }
178
191
 
179
- const response = await fetch(this.getUrl(path, queryString), {
180
- headers: this.headers,
181
- })
182
-
183
- return await this.parseResponse(response)
184
- }
192
+ if (disabledHeaders) {
193
+ for (let headerKey of Object.keys(this.headers)) {
194
+ if (disabledHeaders[headerKey]) {
195
+ delete this.headers[headerKey]
196
+ }
197
+ }
198
+ }
185
199
 
186
- async update({ path = "", queryString = "", headers = {}, json = {} }) {
187
- this.headers = {
188
- ...this.config.defaultHeaders,
189
- ...headers,
200
+ let json
201
+ if (bodyType === BodyTypes.JSON && requestBody) {
202
+ try {
203
+ json = JSON.parse(requestBody)
204
+ } catch (err) {
205
+ throw "Invalid JSON for request body"
206
+ }
190
207
  }
191
208
 
192
- const response = await fetch(this.getUrl(path, queryString), {
193
- method: "PUT",
194
- headers: this.headers,
195
- body: JSON.stringify(json),
196
- })
209
+ const input: any = { method, headers: this.headers }
210
+ if (json && typeof json === "object" && Object.keys(json).length > 0) {
211
+ input.body = JSON.stringify(json)
212
+ }
197
213
 
214
+ this.startTimeMs = performance.now()
215
+ const url = this.getUrl(path, queryString)
216
+ const response = await fetch(url, input)
198
217
  return await this.parseResponse(response)
199
218
  }
200
219
 
201
- async patch({ path = "", queryString = "", headers = {}, json = {} }) {
202
- this.headers = {
203
- ...this.config.defaultHeaders,
204
- ...headers,
205
- }
206
-
207
- const response = await fetch(this.getUrl(path, queryString), {
208
- method: "PATCH",
209
- headers: this.headers,
210
- body: JSON.stringify(json),
211
- })
220
+ async create(opts: RestQuery) {
221
+ return this._req({ ...opts, method: "POST" })
222
+ }
212
223
 
213
- return await this.parseResponse(response)
224
+ async read(opts: RestQuery) {
225
+ return this._req({ ...opts, method: "GET" })
214
226
  }
215
227
 
216
- async delete({ path = "", queryString = "", headers = {} }) {
217
- this.headers = {
218
- ...this.config.defaultHeaders,
219
- ...headers,
220
- }
228
+ async update(opts: RestQuery) {
229
+ return this._req({ ...opts, method: "PUT" })
230
+ }
221
231
 
222
- const response = await fetch(this.getUrl(path, queryString), {
223
- method: "DELETE",
224
- headers: this.headers,
225
- })
232
+ async patch(opts: RestQuery) {
233
+ return this._req({ ...opts, method: "PATCH" })
234
+ }
226
235
 
227
- return await this.parseResponse(response)
236
+ async delete(opts: RestQuery) {
237
+ return this._req({ ...opts, method: "DELETE" })
228
238
  }
229
239
  }
230
240
 
231
241
  module.exports = {
232
242
  schema: SCHEMA,
233
243
  integration: RestIntegration,
244
+ AuthType,
234
245
  }
235
246
  }
@@ -1,6 +1,9 @@
1
1
  jest.mock("node-fetch", () =>
2
2
  jest.fn(() => ({
3
3
  headers: {
4
+ raw: () => {
5
+ return { "content-type": ["application/json"] }
6
+ },
4
7
  get: () => ["application/json"]
5
8
  },
6
9
  json: jest.fn(),
@@ -9,6 +12,7 @@ jest.mock("node-fetch", () =>
9
12
  )
10
13
  const fetch = require("node-fetch")
11
14
  const RestIntegration = require("../rest")
15
+ const { AuthType } = require("../rest")
12
16
 
13
17
  class TestConfiguration {
14
18
  constructor(config = {}) {
@@ -24,6 +28,7 @@ describe("REST Integration", () => {
24
28
  config = new TestConfiguration({
25
29
  url: BASE_URL,
26
30
  })
31
+ jest.clearAllMocks()
27
32
  })
28
33
 
29
34
  it("calls the create method with the correct params", async () => {
@@ -33,9 +38,10 @@ describe("REST Integration", () => {
33
38
  headers: {
34
39
  Accept: "application/json",
35
40
  },
36
- json: {
41
+ bodyType: "json",
42
+ requestBody: JSON.stringify({
37
43
  name: "test",
38
- },
44
+ }),
39
45
  }
40
46
  const response = await config.integration.create(query)
41
47
  expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
@@ -60,6 +66,7 @@ describe("REST Integration", () => {
60
66
  headers: {
61
67
  Accept: "text/html",
62
68
  },
69
+ method: "GET",
63
70
  })
64
71
  })
65
72
 
@@ -70,13 +77,14 @@ describe("REST Integration", () => {
70
77
  headers: {
71
78
  Accept: "application/json",
72
79
  },
73
- json: {
80
+ bodyType: "json",
81
+ requestBody: JSON.stringify({
74
82
  name: "test",
75
- },
83
+ }),
76
84
  }
77
85
  const response = await config.integration.update(query)
78
86
  expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
79
- method: "POST",
87
+ method: "PUT",
80
88
  body: '{"name":"test"}',
81
89
  headers: {
82
90
  Accept: "application/json",
@@ -91,9 +99,10 @@ describe("REST Integration", () => {
91
99
  headers: {
92
100
  Accept: "application/json",
93
101
  },
94
- json: {
102
+ bodyType: "json",
103
+ requestBody: JSON.stringify({
95
104
  name: "test",
96
- },
105
+ }),
97
106
  }
98
107
  const response = await config.integration.delete(query)
99
108
  expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?test=1`, {
@@ -101,6 +110,61 @@ describe("REST Integration", () => {
101
110
  headers: {
102
111
  Accept: "application/json",
103
112
  },
113
+ body: '{"name":"test"}',
114
+ })
115
+ })
116
+
117
+ describe("authentication", () => {
118
+ const basicAuth = {
119
+ _id: "c59c14bd1898a43baa08da68959b24686",
120
+ name: "basic-1",
121
+ type : AuthType.BASIC,
122
+ config : {
123
+ username: "user",
124
+ password: "password"
125
+ }
126
+ }
127
+
128
+ const bearerAuth = {
129
+ _id: "0d91d732f34e4befabeff50b392a8ff3",
130
+ name: "bearer-1",
131
+ type : AuthType.BEARER,
132
+ config : {
133
+ "token": "mytoken"
134
+ }
135
+ }
136
+
137
+ beforeEach(() => {
138
+ config = new TestConfiguration({
139
+ url: BASE_URL,
140
+ authConfigs : [basicAuth, bearerAuth]
141
+ })
142
+ })
143
+
144
+ it("adds basic auth", async () => {
145
+ const query = {
146
+ authConfigId: "c59c14bd1898a43baa08da68959b24686"
147
+ }
148
+ await config.integration.read(query)
149
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/?`, {
150
+ method: "GET",
151
+ headers: {
152
+ Authorization: "Basic dXNlcjpwYXNzd29yZA=="
153
+ },
154
+ })
155
+ })
156
+
157
+ it("adds bearer auth", async () => {
158
+ const query = {
159
+ authConfigId: "0d91d732f34e4befabeff50b392a8ff3"
160
+ }
161
+ await config.integration.read(query)
162
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/?`, {
163
+ method: "GET",
164
+ headers: {
165
+ Authorization: "Bearer mytoken"
166
+ },
167
+ })
104
168
  })
105
169
  })
106
170
  })
@@ -15,6 +15,15 @@ function formatResponse(resp) {
15
15
  return resp
16
16
  }
17
17
 
18
+ function hasExtraData(response) {
19
+ return (
20
+ typeof response === "object" &&
21
+ !Array.isArray(response) &&
22
+ response.data != null &&
23
+ response.info != null
24
+ )
25
+ }
26
+
18
27
  async function runAndTransform(datasource, queryVerb, query, transformer) {
19
28
  const Integration = integrations[datasource.source]
20
29
  if (!Integration) {
@@ -22,7 +31,15 @@ async function runAndTransform(datasource, queryVerb, query, transformer) {
22
31
  }
23
32
  const integration = new Integration(datasource.config)
24
33
 
25
- let rows = formatResponse(await integration[queryVerb](query))
34
+ let output = formatResponse(await integration[queryVerb](query))
35
+ let rows = output,
36
+ info = undefined,
37
+ extra = undefined
38
+ if (hasExtraData(output)) {
39
+ rows = output.data
40
+ info = output.info
41
+ extra = output.extra
42
+ }
26
43
 
27
44
  // transform as required
28
45
  if (transformer) {
@@ -47,7 +64,7 @@ async function runAndTransform(datasource, queryVerb, query, transformer) {
47
64
  integration.end()
48
65
  }
49
66
 
50
- return { rows, keys }
67
+ return { rows, keys, info, extra }
51
68
  }
52
69
 
53
70
  module.exports = (input, callback) => {
@@ -150,3 +150,14 @@ exports.doesDatabaseExist = async dbName => {
150
150
  return false
151
151
  }
152
152
  }
153
+
154
+ exports.formatBytes = bytes => {
155
+ const units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
156
+ const byteIncrements = 1024
157
+ let unit = 0
158
+ let size = parseInt(bytes, 10) || 0
159
+ while (size >= byteIncrements && ++unit) {
160
+ size /= byteIncrements
161
+ }
162
+ return `${size.toFixed(size < 10 && unit > 0 ? 1 : 0)}${units[unit]}`
163
+ }