@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
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  DatasourceFieldType,
3
+ DatasourcePlus,
3
4
  Integration,
5
+ QueryJson,
4
6
  QueryType,
5
7
  Table,
6
8
  TableSchema,
7
- QueryJson,
8
- DatasourcePlus,
9
9
  } from "@budibase/types"
10
10
  import { OAuth2Client } from "google-auth-library"
11
11
  import { buildExternalTableId } from "./utils"
@@ -13,410 +13,400 @@ import { DataSourceOperation, FieldTypes } from "../constants"
13
13
  import { GoogleSpreadsheet } from "google-spreadsheet"
14
14
  import env from "../environment"
15
15
 
16
- module GoogleSheetsModule {
17
- const { getGlobalDB } = require("@budibase/backend-core/tenancy")
18
- const { getScopedConfig } = require("@budibase/backend-core/db")
19
- const { Configs } = require("@budibase/backend-core/constants")
20
- const fetch = require("node-fetch")
16
+ const { getGlobalDB } = require("@budibase/backend-core/tenancy")
17
+ const { getScopedConfig } = require("@budibase/backend-core/db")
18
+ const { Configs } = require("@budibase/backend-core/constants")
19
+ const fetch = require("node-fetch")
21
20
 
22
- interface GoogleSheetsConfig {
23
- spreadsheetId: string
24
- auth: OAuthClientConfig
25
- }
21
+ interface GoogleSheetsConfig {
22
+ spreadsheetId: string
23
+ auth: OAuthClientConfig
24
+ }
26
25
 
27
- interface OAuthClientConfig {
28
- appId: string
29
- accessToken: string
30
- refreshToken: string
31
- }
26
+ interface OAuthClientConfig {
27
+ appId: string
28
+ accessToken: string
29
+ refreshToken: string
30
+ }
32
31
 
33
- interface AuthTokenRequest {
34
- client_id: string
35
- client_secret: string
36
- refresh_token: string
37
- }
32
+ interface AuthTokenRequest {
33
+ client_id: string
34
+ client_secret: string
35
+ refresh_token: string
36
+ }
38
37
 
39
- interface AuthTokenResponse {
40
- access_token: string
41
- }
38
+ interface AuthTokenResponse {
39
+ access_token: string
40
+ }
42
41
 
43
- const SCHEMA: Integration = {
44
- plus: true,
45
- auth: {
46
- type: "google",
42
+ const SCHEMA: Integration = {
43
+ plus: true,
44
+ auth: {
45
+ type: "google",
46
+ },
47
+ relationships: false,
48
+ docs: "https://developers.google.com/sheets/api/quickstart/nodejs",
49
+ description:
50
+ "Create and collaborate on online spreadsheets in real-time and from any device. ",
51
+ friendlyName: "Google Sheets",
52
+ type: "Spreadsheet",
53
+ datasource: {
54
+ spreadsheetId: {
55
+ display: "Google Sheet URL",
56
+ type: DatasourceFieldType.STRING,
57
+ required: true,
47
58
  },
48
- relationships: false,
49
- docs: "https://developers.google.com/sheets/api/quickstart/nodejs",
50
- description:
51
- "Create and collaborate on online spreadsheets in real-time and from any device. ",
52
- friendlyName: "Google Sheets",
53
- type: "Spreadsheet",
54
- datasource: {
55
- spreadsheetId: {
56
- display: "Google Sheet URL",
57
- type: DatasourceFieldType.STRING,
58
- required: true,
59
+ },
60
+ query: {
61
+ create: {
62
+ type: QueryType.FIELDS,
63
+ fields: {
64
+ sheet: {
65
+ type: DatasourceFieldType.STRING,
66
+ required: true,
67
+ },
68
+ row: {
69
+ type: QueryType.JSON,
70
+ required: true,
71
+ },
59
72
  },
60
73
  },
61
- query: {
62
- create: {
63
- type: QueryType.FIELDS,
64
- fields: {
65
- sheet: {
66
- type: DatasourceFieldType.STRING,
67
- required: true,
68
- },
69
- row: {
70
- type: QueryType.JSON,
71
- required: true,
72
- },
74
+ read: {
75
+ type: QueryType.FIELDS,
76
+ fields: {
77
+ sheet: {
78
+ type: DatasourceFieldType.STRING,
79
+ required: true,
73
80
  },
74
81
  },
75
- read: {
76
- type: QueryType.FIELDS,
77
- fields: {
78
- sheet: {
79
- type: DatasourceFieldType.STRING,
80
- required: true,
81
- },
82
+ },
83
+ update: {
84
+ type: QueryType.FIELDS,
85
+ fields: {
86
+ sheet: {
87
+ type: DatasourceFieldType.STRING,
88
+ required: true,
82
89
  },
83
- },
84
- update: {
85
- type: QueryType.FIELDS,
86
- fields: {
87
- sheet: {
88
- type: DatasourceFieldType.STRING,
89
- required: true,
90
- },
91
- rowIndex: {
92
- type: DatasourceFieldType.STRING,
93
- required: true,
94
- },
95
- row: {
96
- type: QueryType.JSON,
97
- required: true,
98
- },
90
+ rowIndex: {
91
+ type: DatasourceFieldType.STRING,
92
+ required: true,
93
+ },
94
+ row: {
95
+ type: QueryType.JSON,
96
+ required: true,
99
97
  },
100
98
  },
101
- delete: {
102
- type: QueryType.FIELDS,
103
- fields: {
104
- sheet: {
105
- type: DatasourceFieldType.STRING,
106
- required: true,
107
- },
108
- rowIndex: {
109
- type: DatasourceFieldType.NUMBER,
110
- required: true,
111
- },
99
+ },
100
+ delete: {
101
+ type: QueryType.FIELDS,
102
+ fields: {
103
+ sheet: {
104
+ type: DatasourceFieldType.STRING,
105
+ required: true,
106
+ },
107
+ rowIndex: {
108
+ type: DatasourceFieldType.NUMBER,
109
+ required: true,
112
110
  },
113
111
  },
114
112
  },
113
+ },
114
+ }
115
+
116
+ class GoogleSheetsIntegration implements DatasourcePlus {
117
+ private readonly config: GoogleSheetsConfig
118
+ private client: any
119
+ public tables: Record<string, Table> = {}
120
+ public schemaErrors: Record<string, string> = {}
121
+
122
+ constructor(config: GoogleSheetsConfig) {
123
+ this.config = config
124
+ const spreadsheetId = this.cleanSpreadsheetUrl(this.config.spreadsheetId)
125
+ this.client = new GoogleSpreadsheet(spreadsheetId)
115
126
  }
116
127
 
117
- class GoogleSheetsIntegration implements DatasourcePlus {
118
- private readonly config: GoogleSheetsConfig
119
- private client: any
120
- public tables: Record<string, Table> = {}
121
- public schemaErrors: Record<string, string> = {}
128
+ getBindingIdentifier() {
129
+ return ""
130
+ }
122
131
 
123
- constructor(config: GoogleSheetsConfig) {
124
- this.config = config
125
- const spreadsheetId = this.cleanSpreadsheetUrl(this.config.spreadsheetId)
126
- this.client = new GoogleSpreadsheet(spreadsheetId)
127
- }
132
+ getStringConcat(parts: string[]) {
133
+ return ""
134
+ }
128
135
 
129
- getBindingIdentifier() {
130
- return ""
136
+ /**
137
+ * Pull the spreadsheet ID out from a valid google sheets URL
138
+ * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet
139
+ * @returns spreadsheet Id of the google sheet
140
+ */
141
+ cleanSpreadsheetUrl(spreadsheetId: string) {
142
+ if (!spreadsheetId) {
143
+ throw new Error(
144
+ "You must set a spreadsheet ID in your configuration to fetch tables."
145
+ )
131
146
  }
147
+ const parts = spreadsheetId.split("/")
148
+ return parts.length > 5 ? parts[5] : spreadsheetId
149
+ }
132
150
 
133
- getStringConcat(parts: string[]) {
134
- return ""
135
- }
151
+ async fetchAccessToken(
152
+ payload: AuthTokenRequest
153
+ ): Promise<AuthTokenResponse> {
154
+ const response = await fetch("https://www.googleapis.com/oauth2/v4/token", {
155
+ method: "POST",
156
+ body: JSON.stringify({
157
+ ...payload,
158
+ grant_type: "refresh_token",
159
+ }),
160
+ headers: {
161
+ "Content-Type": "application/json",
162
+ },
163
+ })
136
164
 
137
- /**
138
- * Pull the spreadsheet ID out from a valid google sheets URL
139
- * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet
140
- * @returns spreadsheet Id of the google sheet
141
- */
142
- cleanSpreadsheetUrl(spreadsheetId: string) {
143
- if (!spreadsheetId) {
144
- throw new Error(
145
- "You must set a spreadsheet ID in your configuration to fetch tables."
146
- )
147
- }
148
- const parts = spreadsheetId.split("/")
149
- return parts.length > 5 ? parts[5] : spreadsheetId
150
- }
165
+ const json = await response.json()
151
166
 
152
- async fetchAccessToken(
153
- payload: AuthTokenRequest
154
- ): Promise<AuthTokenResponse> {
155
- const response = await fetch(
156
- "https://www.googleapis.com/oauth2/v4/token",
157
- {
158
- method: "POST",
159
- body: JSON.stringify({
160
- ...payload,
161
- grant_type: "refresh_token",
162
- }),
163
- headers: {
164
- "Content-Type": "application/json",
165
- },
166
- }
167
+ if (response.status !== 200) {
168
+ throw new Error(
169
+ `Error authenticating with google sheets. ${json.error_description}`
167
170
  )
171
+ }
168
172
 
169
- const json = await response.json()
173
+ return json
174
+ }
170
175
 
171
- if (response.status !== 200) {
172
- throw new Error(
173
- `Error authenticating with google sheets. ${json.error_description}`
174
- )
176
+ async connect() {
177
+ try {
178
+ // Initialise oAuth client
179
+ const db = getGlobalDB()
180
+ let googleConfig = await getScopedConfig(db, {
181
+ type: Configs.GOOGLE,
182
+ })
183
+
184
+ if (!googleConfig) {
185
+ googleConfig = {
186
+ clientID: env.GOOGLE_CLIENT_ID,
187
+ clientSecret: env.GOOGLE_CLIENT_SECRET,
188
+ }
175
189
  }
176
190
 
177
- return json
191
+ const oauthClient = new OAuth2Client({
192
+ clientId: googleConfig.clientID,
193
+ clientSecret: googleConfig.clientSecret,
194
+ })
195
+
196
+ const tokenResponse = await this.fetchAccessToken({
197
+ client_id: googleConfig.clientID,
198
+ client_secret: googleConfig.clientSecret,
199
+ refresh_token: this.config.auth.refreshToken,
200
+ })
201
+
202
+ oauthClient.setCredentials({
203
+ refresh_token: this.config.auth.refreshToken,
204
+ access_token: tokenResponse.access_token,
205
+ })
206
+
207
+ this.client.useOAuth2Client(oauthClient)
208
+ await this.client.loadInfo()
209
+ } catch (err) {
210
+ console.error("Error connecting to google sheets", err)
211
+ throw err
178
212
  }
213
+ }
179
214
 
180
- async connect() {
181
- try {
182
- // Initialise oAuth client
183
- const db = getGlobalDB()
184
- let googleConfig = await getScopedConfig(db, {
185
- type: Configs.GOOGLE,
186
- })
187
-
188
- if (!googleConfig) {
189
- googleConfig = {
190
- clientID: env.GOOGLE_CLIENT_ID,
191
- clientSecret: env.GOOGLE_CLIENT_SECRET,
192
- }
215
+ async buildSchema(datasourceId: string) {
216
+ await this.connect()
217
+ const sheets = await this.client.sheetsByIndex
218
+ const tables: Record<string, Table> = {}
219
+ for (let sheet of sheets) {
220
+ // must fetch rows to determine schema
221
+ await sheet.getRows()
222
+ // build schema
223
+ const schema: TableSchema = {}
224
+
225
+ // build schema from headers
226
+ for (let header of sheet.headerValues) {
227
+ schema[header] = {
228
+ name: header,
229
+ type: FieldTypes.STRING,
193
230
  }
231
+ }
194
232
 
195
- const oauthClient = new OAuth2Client({
196
- clientId: googleConfig.clientID,
197
- clientSecret: googleConfig.clientSecret,
198
- })
199
-
200
- const tokenResponse = await this.fetchAccessToken({
201
- client_id: googleConfig.clientID,
202
- client_secret: googleConfig.clientSecret,
203
- refresh_token: this.config.auth.refreshToken,
204
- })
205
-
206
- oauthClient.setCredentials({
207
- refresh_token: this.config.auth.refreshToken,
208
- access_token: tokenResponse.access_token,
209
- })
210
-
211
- this.client.useOAuth2Client(oauthClient)
212
- await this.client.loadInfo()
213
- } catch (err) {
214
- console.error("Error connecting to google sheets", err)
215
- throw err
233
+ // create tables
234
+ tables[sheet.title] = {
235
+ _id: buildExternalTableId(datasourceId, sheet.title),
236
+ name: sheet.title,
237
+ primary: ["rowNumber"],
238
+ schema,
216
239
  }
217
240
  }
218
241
 
219
- async buildSchema(datasourceId: string) {
220
- await this.connect()
221
- const sheets = await this.client.sheetsByIndex
222
- const tables: Record<string, Table> = {}
223
- for (let sheet of sheets) {
224
- // must fetch rows to determine schema
225
- await sheet.getRows()
226
- // build schema
227
- const schema: TableSchema = {}
228
-
229
- // build schema from headers
230
- for (let header of sheet.headerValues) {
231
- schema[header] = {
232
- name: header,
233
- type: FieldTypes.STRING,
234
- }
235
- }
236
-
237
- // create tables
238
- tables[sheet.title] = {
239
- _id: buildExternalTableId(datasourceId, sheet.title),
240
- name: sheet.title,
241
- primary: ["rowNumber"],
242
- schema,
243
- }
244
- }
242
+ this.tables = tables
243
+ }
245
244
 
246
- this.tables = tables
245
+ async query(json: QueryJson) {
246
+ const sheet = json.endpoint.entityId
247
+
248
+ const handlers = {
249
+ [DataSourceOperation.CREATE]: () =>
250
+ this.create({ sheet, row: json.body }),
251
+ [DataSourceOperation.READ]: () => this.read({ sheet }),
252
+ [DataSourceOperation.UPDATE]: () =>
253
+ this.update({
254
+ // exclude the header row and zero index
255
+ rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
256
+ sheet,
257
+ row: json.body,
258
+ }),
259
+ [DataSourceOperation.DELETE]: () =>
260
+ this.delete({
261
+ // exclude the header row and zero index
262
+ rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
263
+ sheet,
264
+ }),
265
+ [DataSourceOperation.CREATE_TABLE]: () =>
266
+ this.createTable(json?.table?.name),
267
+ [DataSourceOperation.UPDATE_TABLE]: () => this.updateTable(json.table),
268
+ [DataSourceOperation.DELETE_TABLE]: () =>
269
+ this.deleteTable(json?.table?.name),
247
270
  }
248
271
 
249
- async query(json: QueryJson) {
250
- const sheet = json.endpoint.entityId
251
-
252
- const handlers = {
253
- [DataSourceOperation.CREATE]: () =>
254
- this.create({ sheet, row: json.body }),
255
- [DataSourceOperation.READ]: () => this.read({ sheet }),
256
- [DataSourceOperation.UPDATE]: () =>
257
- this.update({
258
- // exclude the header row and zero index
259
- rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
260
- sheet,
261
- row: json.body,
262
- }),
263
- [DataSourceOperation.DELETE]: () =>
264
- this.delete({
265
- // exclude the header row and zero index
266
- rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
267
- sheet,
268
- }),
269
- [DataSourceOperation.CREATE_TABLE]: () =>
270
- this.createTable(json?.table?.name),
271
- [DataSourceOperation.UPDATE_TABLE]: () => this.updateTable(json.table),
272
- [DataSourceOperation.DELETE_TABLE]: () =>
273
- this.deleteTable(json?.table?.name),
274
- }
272
+ const internalQueryMethod = handlers[json.endpoint.operation]
275
273
 
276
- const internalQueryMethod = handlers[json.endpoint.operation]
274
+ return await internalQueryMethod()
275
+ }
277
276
 
278
- return await internalQueryMethod()
277
+ buildRowObject(headers: string[], values: string[], rowNumber: number) {
278
+ const rowObject: { rowNumber: number; [key: string]: any } = { rowNumber }
279
+ for (let i = 0; i < headers.length; i++) {
280
+ rowObject._id = rowNumber
281
+ rowObject[headers[i]] = values[i]
279
282
  }
283
+ return rowObject
284
+ }
280
285
 
281
- buildRowObject(headers: string[], values: string[], rowNumber: number) {
282
- const rowObject: { rowNumber: number; [key: string]: any } = { rowNumber }
283
- for (let i = 0; i < headers.length; i++) {
284
- rowObject._id = rowNumber
285
- rowObject[headers[i]] = values[i]
286
- }
287
- return rowObject
286
+ async createTable(name?: string) {
287
+ try {
288
+ await this.connect()
289
+ return await this.client.addSheet({ title: name })
290
+ } catch (err) {
291
+ console.error("Error creating new table in google sheets", err)
292
+ throw err
288
293
  }
294
+ }
289
295
 
290
- async createTable(name?: string) {
291
- try {
292
- await this.connect()
293
- const sheet = await this.client.addSheet({ title: name })
294
- return sheet
295
- } catch (err) {
296
- console.error("Error creating new table in google sheets", err)
297
- throw err
298
- }
299
- }
296
+ async updateTable(table?: any) {
297
+ try {
298
+ await this.connect()
299
+ const sheet = await this.client.sheetsByTitle[table.name]
300
+ await sheet.loadHeaderRow()
300
301
 
301
- async updateTable(table?: any) {
302
- try {
303
- await this.connect()
304
- const sheet = await this.client.sheetsByTitle[table.name]
305
- await sheet.loadHeaderRow()
306
-
307
- if (table._rename) {
308
- const headers = []
309
- for (let header of sheet.headerValues) {
310
- if (header === table._rename.old) {
311
- headers.push(table._rename.updated)
312
- } else {
313
- headers.push(header)
314
- }
302
+ if (table._rename) {
303
+ const headers = []
304
+ for (let header of sheet.headerValues) {
305
+ if (header === table._rename.old) {
306
+ headers.push(table._rename.updated)
307
+ } else {
308
+ headers.push(header)
315
309
  }
316
- await sheet.setHeaderRow(headers)
317
- } else {
318
- let newField = Object.keys(table.schema).find(
319
- key => !sheet.headerValues.includes(key)
320
- )
321
- await sheet.setHeaderRow([...sheet.headerValues, newField])
322
310
  }
323
- } catch (err) {
324
- console.error("Error updating table in google sheets", err)
325
- throw err
326
- }
327
- }
328
-
329
- async deleteTable(sheet: any) {
330
- try {
331
- await this.connect()
332
- const sheetToDelete = await this.client.sheetsByTitle[sheet]
333
- return await sheetToDelete.delete()
334
- } catch (err) {
335
- console.error("Error deleting table in google sheets", err)
336
- throw err
311
+ await sheet.setHeaderRow(headers)
312
+ } else {
313
+ let newField = Object.keys(table.schema).find(
314
+ key => !sheet.headerValues.includes(key)
315
+ )
316
+ await sheet.setHeaderRow([...sheet.headerValues, newField])
337
317
  }
318
+ } catch (err) {
319
+ console.error("Error updating table in google sheets", err)
320
+ throw err
338
321
  }
322
+ }
339
323
 
340
- async create(query: { sheet: string; row: any }) {
341
- try {
342
- await this.connect()
343
- const sheet = await this.client.sheetsByTitle[query.sheet]
344
- const rowToInsert =
345
- typeof query.row === "string" ? JSON.parse(query.row) : query.row
346
- const row = await sheet.addRow(rowToInsert)
347
- return [
348
- this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
349
- ]
350
- } catch (err) {
351
- console.error("Error writing to google sheets", err)
352
- throw err
353
- }
324
+ async deleteTable(sheet: any) {
325
+ try {
326
+ await this.connect()
327
+ const sheetToDelete = await this.client.sheetsByTitle[sheet]
328
+ return await sheetToDelete.delete()
329
+ } catch (err) {
330
+ console.error("Error deleting table in google sheets", err)
331
+ throw err
354
332
  }
333
+ }
355
334
 
356
- async read(query: { sheet: string }) {
357
- try {
358
- await this.connect()
359
- const sheet = await this.client.sheetsByTitle[query.sheet]
360
- const rows = await sheet.getRows()
361
- const headerValues = sheet.headerValues
362
- const response = []
363
- for (let row of rows) {
364
- response.push(
365
- this.buildRowObject(headerValues, row._rawData, row._rowNumber)
366
- )
367
- }
368
- return response
369
- } catch (err) {
370
- console.error("Error reading from google sheets", err)
371
- throw err
372
- }
335
+ async create(query: { sheet: string; row: any }) {
336
+ try {
337
+ await this.connect()
338
+ const sheet = await this.client.sheetsByTitle[query.sheet]
339
+ const rowToInsert =
340
+ typeof query.row === "string" ? JSON.parse(query.row) : query.row
341
+ const row = await sheet.addRow(rowToInsert)
342
+ return [
343
+ this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
344
+ ]
345
+ } catch (err) {
346
+ console.error("Error writing to google sheets", err)
347
+ throw err
373
348
  }
349
+ }
374
350
 
375
- async update(query: { sheet: string; rowIndex: number; row: any }) {
376
- try {
377
- await this.connect()
378
- const sheet = await this.client.sheetsByTitle[query.sheet]
379
- const rows = await sheet.getRows()
380
- const row = rows[query.rowIndex]
381
- if (row) {
382
- const updateValues =
383
- typeof query.row === "string" ? JSON.parse(query.row) : query.row
384
- for (let key in updateValues) {
385
- row[key] = updateValues[key]
386
- }
387
- await row.save()
388
- return [
389
- this.buildRowObject(
390
- sheet.headerValues,
391
- row._rawData,
392
- row._rowNumber
393
- ),
394
- ]
395
- } else {
396
- throw new Error("Row does not exist.")
397
- }
398
- } catch (err) {
399
- console.error("Error reading from google sheets", err)
400
- throw err
351
+ async read(query: { sheet: string }) {
352
+ try {
353
+ await this.connect()
354
+ const sheet = await this.client.sheetsByTitle[query.sheet]
355
+ const rows = await sheet.getRows()
356
+ const headerValues = sheet.headerValues
357
+ const response = []
358
+ for (let row of rows) {
359
+ response.push(
360
+ this.buildRowObject(headerValues, row._rawData, row._rowNumber)
361
+ )
401
362
  }
363
+ return response
364
+ } catch (err) {
365
+ console.error("Error reading from google sheets", err)
366
+ throw err
402
367
  }
368
+ }
403
369
 
404
- async delete(query: { sheet: string; rowIndex: number }) {
370
+ async update(query: { sheet: string; rowIndex: number; row: any }) {
371
+ try {
405
372
  await this.connect()
406
373
  const sheet = await this.client.sheetsByTitle[query.sheet]
407
374
  const rows = await sheet.getRows()
408
375
  const row = rows[query.rowIndex]
409
376
  if (row) {
410
- await row.delete()
411
- return [{ deleted: query.rowIndex }]
377
+ const updateValues =
378
+ typeof query.row === "string" ? JSON.parse(query.row) : query.row
379
+ for (let key in updateValues) {
380
+ row[key] = updateValues[key]
381
+ }
382
+ await row.save()
383
+ return [
384
+ this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
385
+ ]
412
386
  } else {
413
387
  throw new Error("Row does not exist.")
414
388
  }
389
+ } catch (err) {
390
+ console.error("Error reading from google sheets", err)
391
+ throw err
415
392
  }
416
393
  }
417
394
 
418
- module.exports = {
419
- schema: SCHEMA,
420
- integration: GoogleSheetsIntegration,
395
+ async delete(query: { sheet: string; rowIndex: number }) {
396
+ await this.connect()
397
+ const sheet = await this.client.sheetsByTitle[query.sheet]
398
+ const rows = await sheet.getRows()
399
+ const row = rows[query.rowIndex]
400
+ if (row) {
401
+ await row.delete()
402
+ return [{ deleted: query.rowIndex }]
403
+ } else {
404
+ throw new Error("Row does not exist.")
405
+ }
421
406
  }
422
407
  }
408
+
409
+ export default {
410
+ schema: SCHEMA,
411
+ integration: GoogleSheetsIntegration,
412
+ }