@budibase/backend-core 2.9.19-alpha.0 → 2.9.20

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/dist/index.js +324 -266
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +19 -4
  5. package/dist/plugins.js +1 -1
  6. package/dist/plugins.js.map +1 -1
  7. package/dist/plugins.js.meta.json +1 -1
  8. package/dist/src/security/permissions.d.ts +1 -1
  9. package/dist/tests.js +260 -222
  10. package/dist/tests.js.map +4 -4
  11. package/dist/tests.js.meta.json +1 -1
  12. package/package.json +19 -4
  13. package/__mocks__/aws-sdk.ts +0 -18
  14. package/dist/tsconfig.build.tsbuildinfo +0 -1
  15. package/jest-testcontainers-config.js +0 -8
  16. package/jest.config.ts +0 -35
  17. package/scripts/build.js +0 -6
  18. package/scripts/test.sh +0 -13
  19. package/src/accounts/accounts.ts +0 -82
  20. package/src/accounts/api.ts +0 -59
  21. package/src/accounts/index.ts +0 -1
  22. package/src/auth/auth.ts +0 -208
  23. package/src/auth/index.ts +0 -1
  24. package/src/auth/tests/auth.spec.ts +0 -14
  25. package/src/blacklist/blacklist.ts +0 -54
  26. package/src/blacklist/index.ts +0 -1
  27. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  28. package/src/cache/appMetadata.ts +0 -88
  29. package/src/cache/base/index.ts +0 -92
  30. package/src/cache/generic.ts +0 -30
  31. package/src/cache/index.ts +0 -5
  32. package/src/cache/tests/writethrough.spec.ts +0 -138
  33. package/src/cache/user.ts +0 -69
  34. package/src/cache/writethrough.ts +0 -133
  35. package/src/configs/configs.ts +0 -257
  36. package/src/configs/index.ts +0 -1
  37. package/src/configs/tests/configs.spec.ts +0 -184
  38. package/src/constants/db.ts +0 -63
  39. package/src/constants/index.ts +0 -2
  40. package/src/constants/misc.ts +0 -50
  41. package/src/context/Context.ts +0 -14
  42. package/src/context/identity.ts +0 -58
  43. package/src/context/index.ts +0 -3
  44. package/src/context/mainContext.ts +0 -310
  45. package/src/context/tests/index.spec.ts +0 -147
  46. package/src/context/types.ts +0 -11
  47. package/src/db/Replication.ts +0 -84
  48. package/src/db/constants.ts +0 -10
  49. package/src/db/couch/DatabaseImpl.ts +0 -238
  50. package/src/db/couch/connections.ts +0 -77
  51. package/src/db/couch/index.ts +0 -5
  52. package/src/db/couch/pouchDB.ts +0 -97
  53. package/src/db/couch/pouchDump.ts +0 -0
  54. package/src/db/couch/utils.ts +0 -50
  55. package/src/db/db.ts +0 -39
  56. package/src/db/errors.ts +0 -14
  57. package/src/db/index.ts +0 -12
  58. package/src/db/lucene.ts +0 -732
  59. package/src/db/searchIndexes/index.ts +0 -1
  60. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  61. package/src/db/tests/index.spec.js +0 -25
  62. package/src/db/tests/lucene.spec.ts +0 -298
  63. package/src/db/tests/pouch.spec.js +0 -62
  64. package/src/db/tests/utils.spec.ts +0 -63
  65. package/src/db/utils.ts +0 -207
  66. package/src/db/views.ts +0 -241
  67. package/src/docIds/conversions.ts +0 -59
  68. package/src/docIds/ids.ts +0 -113
  69. package/src/docIds/index.ts +0 -2
  70. package/src/docIds/newid.ts +0 -5
  71. package/src/docIds/params.ts +0 -174
  72. package/src/docUpdates/index.ts +0 -29
  73. package/src/environment.ts +0 -201
  74. package/src/errors/errors.ts +0 -119
  75. package/src/errors/index.ts +0 -1
  76. package/src/events/analytics.ts +0 -6
  77. package/src/events/asyncEvents/index.ts +0 -2
  78. package/src/events/asyncEvents/publisher.ts +0 -12
  79. package/src/events/asyncEvents/queue.ts +0 -22
  80. package/src/events/backfill.ts +0 -183
  81. package/src/events/documentId.ts +0 -56
  82. package/src/events/events.ts +0 -40
  83. package/src/events/identification.ts +0 -310
  84. package/src/events/index.ts +0 -14
  85. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  86. package/src/events/processors/AuditLogsProcessor.ts +0 -93
  87. package/src/events/processors/LoggingProcessor.ts +0 -37
  88. package/src/events/processors/Processors.ts +0 -52
  89. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -43
  90. package/src/events/processors/index.ts +0 -19
  91. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  92. package/src/events/processors/posthog/index.ts +0 -2
  93. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  94. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -168
  95. package/src/events/processors/types.ts +0 -1
  96. package/src/events/publishers/account.ts +0 -35
  97. package/src/events/publishers/app.ts +0 -155
  98. package/src/events/publishers/auditLog.ts +0 -26
  99. package/src/events/publishers/auth.ts +0 -73
  100. package/src/events/publishers/automation.ts +0 -110
  101. package/src/events/publishers/backfill.ts +0 -74
  102. package/src/events/publishers/backup.ts +0 -42
  103. package/src/events/publishers/datasource.ts +0 -48
  104. package/src/events/publishers/email.ts +0 -17
  105. package/src/events/publishers/environmentVariable.ts +0 -38
  106. package/src/events/publishers/group.ts +0 -99
  107. package/src/events/publishers/index.ts +0 -24
  108. package/src/events/publishers/installation.ts +0 -38
  109. package/src/events/publishers/layout.ts +0 -26
  110. package/src/events/publishers/license.ts +0 -84
  111. package/src/events/publishers/org.ts +0 -37
  112. package/src/events/publishers/plugin.ts +0 -47
  113. package/src/events/publishers/query.ts +0 -88
  114. package/src/events/publishers/role.ts +0 -62
  115. package/src/events/publishers/rows.ts +0 -29
  116. package/src/events/publishers/screen.ts +0 -36
  117. package/src/events/publishers/serve.ts +0 -43
  118. package/src/events/publishers/table.ts +0 -70
  119. package/src/events/publishers/user.ts +0 -202
  120. package/src/events/publishers/view.ts +0 -107
  121. package/src/featureFlags/index.ts +0 -77
  122. package/src/featureFlags/tests/featureFlags.spec.ts +0 -85
  123. package/src/helpers.ts +0 -9
  124. package/src/index.ts +0 -53
  125. package/src/installation.ts +0 -107
  126. package/src/logging/alerts.ts +0 -26
  127. package/src/logging/correlation/correlation.ts +0 -13
  128. package/src/logging/correlation/index.ts +0 -1
  129. package/src/logging/correlation/middleware.ts +0 -17
  130. package/src/logging/index.ts +0 -4
  131. package/src/logging/pino/logger.ts +0 -232
  132. package/src/logging/pino/middleware.ts +0 -45
  133. package/src/logging/system.ts +0 -81
  134. package/src/logging/tests/system.spec.ts +0 -61
  135. package/src/middleware/adminOnly.ts +0 -9
  136. package/src/middleware/auditLog.ts +0 -6
  137. package/src/middleware/authenticated.ts +0 -193
  138. package/src/middleware/builderOnly.ts +0 -20
  139. package/src/middleware/builderOrAdmin.ts +0 -20
  140. package/src/middleware/csrf.ts +0 -81
  141. package/src/middleware/errorHandling.ts +0 -29
  142. package/src/middleware/index.ts +0 -21
  143. package/src/middleware/internalApi.ts +0 -23
  144. package/src/middleware/joi-validator.ts +0 -45
  145. package/src/middleware/matchers.ts +0 -47
  146. package/src/middleware/passport/datasource/google.ts +0 -95
  147. package/src/middleware/passport/local.ts +0 -54
  148. package/src/middleware/passport/sso/google.ts +0 -77
  149. package/src/middleware/passport/sso/oidc.ts +0 -154
  150. package/src/middleware/passport/sso/sso.ts +0 -165
  151. package/src/middleware/passport/sso/tests/google.spec.ts +0 -67
  152. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -152
  153. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  154. package/src/middleware/passport/utils.ts +0 -38
  155. package/src/middleware/querystringToBody.ts +0 -28
  156. package/src/middleware/tenancy.ts +0 -36
  157. package/src/middleware/tests/builder.spec.ts +0 -180
  158. package/src/middleware/tests/matchers.spec.ts +0 -134
  159. package/src/migrations/definitions.ts +0 -40
  160. package/src/migrations/index.ts +0 -2
  161. package/src/migrations/migrations.ts +0 -191
  162. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  163. package/src/migrations/tests/migrations.spec.ts +0 -64
  164. package/src/objectStore/buckets/app.ts +0 -40
  165. package/src/objectStore/buckets/global.ts +0 -29
  166. package/src/objectStore/buckets/index.ts +0 -3
  167. package/src/objectStore/buckets/plugins.ts +0 -71
  168. package/src/objectStore/buckets/tests/app.spec.ts +0 -171
  169. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  170. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  171. package/src/objectStore/cloudfront.ts +0 -41
  172. package/src/objectStore/index.ts +0 -3
  173. package/src/objectStore/objectStore.ts +0 -440
  174. package/src/objectStore/utils.ts +0 -27
  175. package/src/platform/index.ts +0 -3
  176. package/src/platform/platformDb.ts +0 -6
  177. package/src/platform/tenants.ts +0 -101
  178. package/src/platform/tests/tenants.spec.ts +0 -26
  179. package/src/platform/users.ts +0 -90
  180. package/src/plugin/index.ts +0 -1
  181. package/src/plugin/tests/validation.spec.ts +0 -83
  182. package/src/plugin/utils.ts +0 -156
  183. package/src/queue/constants.ts +0 -6
  184. package/src/queue/inMemoryQueue.ts +0 -141
  185. package/src/queue/index.ts +0 -2
  186. package/src/queue/listeners.ts +0 -195
  187. package/src/queue/queue.ts +0 -54
  188. package/src/redis/index.ts +0 -6
  189. package/src/redis/init.ts +0 -86
  190. package/src/redis/redis.ts +0 -308
  191. package/src/redis/redlockImpl.ts +0 -139
  192. package/src/redis/utils.ts +0 -117
  193. package/src/security/encryption.ts +0 -179
  194. package/src/security/permissions.ts +0 -159
  195. package/src/security/roles.ts +0 -420
  196. package/src/security/sessions.ts +0 -120
  197. package/src/security/tests/encryption.spec.ts +0 -31
  198. package/src/security/tests/permissions.spec.ts +0 -145
  199. package/src/security/tests/sessions.spec.ts +0 -12
  200. package/src/tenancy/db.ts +0 -6
  201. package/src/tenancy/index.ts +0 -2
  202. package/src/tenancy/tenancy.ts +0 -140
  203. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  204. package/src/timers/index.ts +0 -1
  205. package/src/timers/timers.ts +0 -22
  206. package/src/users/db.ts +0 -460
  207. package/src/users/events.ts +0 -176
  208. package/src/users/index.ts +0 -4
  209. package/src/users/lookup.ts +0 -102
  210. package/src/users/users.ts +0 -276
  211. package/src/users/utils.ts +0 -55
  212. package/src/utils/hashing.ts +0 -14
  213. package/src/utils/index.ts +0 -3
  214. package/src/utils/stringUtils.ts +0 -8
  215. package/src/utils/tests/utils.spec.ts +0 -191
  216. package/src/utils/utils.ts +0 -239
  217. package/tests/core/logging.ts +0 -34
  218. package/tests/core/utilities/index.ts +0 -6
  219. package/tests/core/utilities/jestUtils.ts +0 -30
  220. package/tests/core/utilities/mocks/alerts.ts +0 -3
  221. package/tests/core/utilities/mocks/date.ts +0 -2
  222. package/tests/core/utilities/mocks/events.ts +0 -131
  223. package/tests/core/utilities/mocks/fetch.ts +0 -17
  224. package/tests/core/utilities/mocks/index.ts +0 -10
  225. package/tests/core/utilities/mocks/licenses.ts +0 -107
  226. package/tests/core/utilities/mocks/posthog.ts +0 -7
  227. package/tests/core/utilities/structures/Chance.ts +0 -20
  228. package/tests/core/utilities/structures/accounts.ts +0 -115
  229. package/tests/core/utilities/structures/apps.ts +0 -21
  230. package/tests/core/utilities/structures/common.ts +0 -7
  231. package/tests/core/utilities/structures/db.ts +0 -12
  232. package/tests/core/utilities/structures/documents/index.ts +0 -1
  233. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  234. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  235. package/tests/core/utilities/structures/generator.ts +0 -2
  236. package/tests/core/utilities/structures/index.ts +0 -15
  237. package/tests/core/utilities/structures/koa.ts +0 -16
  238. package/tests/core/utilities/structures/licenses.ts +0 -167
  239. package/tests/core/utilities/structures/plugins.ts +0 -19
  240. package/tests/core/utilities/structures/quotas.ts +0 -67
  241. package/tests/core/utilities/structures/scim.ts +0 -80
  242. package/tests/core/utilities/structures/shared.ts +0 -19
  243. package/tests/core/utilities/structures/sso.ts +0 -119
  244. package/tests/core/utilities/structures/tenants.ts +0 -5
  245. package/tests/core/utilities/structures/userGroups.ts +0 -10
  246. package/tests/core/utilities/structures/users.ts +0 -73
  247. package/tests/core/utilities/testContainerUtils.ts +0 -98
  248. package/tests/core/utilities/utils/index.ts +0 -1
  249. package/tests/core/utilities/utils/time.ts +0 -3
  250. package/tests/extra/DBTestConfiguration.ts +0 -36
  251. package/tests/extra/index.ts +0 -2
  252. package/tests/extra/testEnv.ts +0 -95
  253. package/tests/index.ts +0 -1
  254. package/tests/jestEnv.ts +0 -6
  255. package/tests/jestSetup.ts +0 -28
  256. package/tsconfig.build.json +0 -29
  257. package/tsconfig.json +0 -4
package/src/redis/init.ts DELETED
@@ -1,86 +0,0 @@
1
- import Client from "./redis"
2
- import * as utils from "./utils"
3
-
4
- let userClient: Client,
5
- sessionClient: Client,
6
- appClient: Client,
7
- cacheClient: Client,
8
- writethroughClient: Client,
9
- lockClient: Client,
10
- socketClient: Client
11
-
12
- async function init() {
13
- userClient = await new Client(utils.Databases.USER_CACHE).init()
14
- sessionClient = await new Client(utils.Databases.SESSIONS).init()
15
- appClient = await new Client(utils.Databases.APP_METADATA).init()
16
- cacheClient = await new Client(utils.Databases.GENERIC_CACHE).init()
17
- lockClient = await new Client(utils.Databases.LOCKS).init()
18
- writethroughClient = await new Client(utils.Databases.WRITE_THROUGH).init()
19
- socketClient = await new Client(
20
- utils.Databases.SOCKET_IO,
21
- utils.SelectableDatabase.SOCKET_IO
22
- ).init()
23
- }
24
-
25
- export async function shutdown() {
26
- if (userClient) await userClient.finish()
27
- if (sessionClient) await sessionClient.finish()
28
- if (appClient) await appClient.finish()
29
- if (cacheClient) await cacheClient.finish()
30
- if (writethroughClient) await writethroughClient.finish()
31
- if (lockClient) await lockClient.finish()
32
- if (socketClient) await socketClient.finish()
33
- }
34
-
35
- process.on("exit", async () => {
36
- await shutdown()
37
- })
38
-
39
- export async function getUserClient() {
40
- if (!userClient) {
41
- await init()
42
- }
43
- return userClient
44
- }
45
-
46
- export async function getSessionClient() {
47
- if (!sessionClient) {
48
- await init()
49
- }
50
- return sessionClient
51
- }
52
-
53
- export async function getAppClient() {
54
- if (!appClient) {
55
- await init()
56
- }
57
- return appClient
58
- }
59
-
60
- export async function getCacheClient() {
61
- if (!cacheClient) {
62
- await init()
63
- }
64
- return cacheClient
65
- }
66
-
67
- export async function getWritethroughClient() {
68
- if (!writethroughClient) {
69
- await init()
70
- }
71
- return writethroughClient
72
- }
73
-
74
- export async function getLockClient() {
75
- if (!lockClient) {
76
- await init()
77
- }
78
- return lockClient
79
- }
80
-
81
- export async function getSocketClient() {
82
- if (!socketClient) {
83
- await init()
84
- }
85
- return socketClient
86
- }
@@ -1,308 +0,0 @@
1
- import env from "../environment"
2
- import Redis from "ioredis"
3
- // mock-redis doesn't have any typing
4
- let MockRedis: any | undefined
5
- if (env.MOCK_REDIS) {
6
- try {
7
- // ioredis mock is all in memory
8
- MockRedis = require("ioredis-mock")
9
- } catch (err) {
10
- console.log("Mock redis unavailable")
11
- }
12
- }
13
- import {
14
- addDbPrefix,
15
- removeDbPrefix,
16
- getRedisOptions,
17
- SEPARATOR,
18
- SelectableDatabase,
19
- } from "./utils"
20
- import * as timers from "../timers"
21
-
22
- const RETRY_PERIOD_MS = 2000
23
- const STARTUP_TIMEOUT_MS = 5000
24
- const CLUSTERED = env.REDIS_CLUSTERED
25
- const DEFAULT_SELECT_DB = SelectableDatabase.DEFAULT
26
-
27
- // for testing just generate the client once
28
- let CLOSED = false
29
- let CLIENTS: { [key: number]: any } = {}
30
- 0
31
- let CONNECTED = false
32
-
33
- // mock redis always connected
34
- if (env.MOCK_REDIS) {
35
- CONNECTED = true
36
- }
37
-
38
- function pickClient(selectDb: number): any {
39
- return CLIENTS[selectDb]
40
- }
41
-
42
- function connectionError(
43
- selectDb: number,
44
- timeout: NodeJS.Timeout,
45
- err: Error | string
46
- ) {
47
- // manually shut down, ignore errors
48
- if (CLOSED) {
49
- return
50
- }
51
- pickClient(selectDb).disconnect()
52
- CLOSED = true
53
- // always clear this on error
54
- clearTimeout(timeout)
55
- CONNECTED = false
56
- console.error("Redis connection failed - " + err)
57
- setTimeout(() => {
58
- init()
59
- }, RETRY_PERIOD_MS)
60
- }
61
-
62
- /**
63
- * Inits the system, will error if unable to connect to redis cluster (may take up to 10 seconds) otherwise
64
- * will return the ioredis client which will be ready to use.
65
- */
66
- function init(selectDb = DEFAULT_SELECT_DB) {
67
- const RedisCore = env.MOCK_REDIS && MockRedis ? MockRedis : Redis
68
- let timeout: NodeJS.Timeout
69
- CLOSED = false
70
- let client = pickClient(selectDb)
71
- // already connected, ignore
72
- if (client && CONNECTED) {
73
- return
74
- }
75
- // testing uses a single in memory client
76
- if (env.MOCK_REDIS) {
77
- CLIENTS[selectDb] = new RedisCore(getRedisOptions())
78
- }
79
- // start the timer - only allowed 5 seconds to connect
80
- timeout = setTimeout(() => {
81
- if (!CONNECTED) {
82
- connectionError(
83
- selectDb,
84
- timeout,
85
- "Did not successfully connect in timeout"
86
- )
87
- }
88
- }, STARTUP_TIMEOUT_MS)
89
-
90
- // disconnect any lingering client
91
- if (client) {
92
- client.disconnect()
93
- }
94
- const { redisProtocolUrl, opts, host, port } = getRedisOptions()
95
-
96
- if (CLUSTERED) {
97
- client = new RedisCore.Cluster([{ host, port }], opts)
98
- } else if (redisProtocolUrl) {
99
- client = new RedisCore(redisProtocolUrl)
100
- } else {
101
- client = new RedisCore(opts)
102
- }
103
- // attach handlers
104
- client.on("end", (err: Error) => {
105
- if (env.isTest()) {
106
- // don't try to re-connect in test env
107
- // allow the process to exit
108
- return
109
- }
110
- connectionError(selectDb, timeout, err)
111
- })
112
- client.on("error", (err: Error) => {
113
- connectionError(selectDb, timeout, err)
114
- })
115
- client.on("connect", () => {
116
- clearTimeout(timeout)
117
- CONNECTED = true
118
- })
119
- CLIENTS[selectDb] = client
120
- }
121
-
122
- function waitForConnection(selectDb: number = DEFAULT_SELECT_DB) {
123
- return new Promise(resolve => {
124
- if (pickClient(selectDb) == null) {
125
- init()
126
- } else if (CONNECTED) {
127
- resolve("")
128
- return
129
- }
130
- // check if the connection is ready
131
- const interval = timers.set(() => {
132
- if (CONNECTED) {
133
- timers.clear(interval)
134
- resolve("")
135
- }
136
- }, 500)
137
- })
138
- }
139
-
140
- /**
141
- * Utility function, takes a redis stream and converts it to a promisified response -
142
- * this can only be done with redis streams because they will have an end.
143
- * @param stream A redis stream, specifically as this type of stream will have an end.
144
- * @param client The client to use for further lookups.
145
- * @return {Promise<object>} The final output of the stream
146
- */
147
- function promisifyStream(stream: any, client: RedisWrapper) {
148
- return new Promise((resolve, reject) => {
149
- const outputKeys = new Set()
150
- stream.on("data", (keys: string[]) => {
151
- keys.forEach(key => {
152
- outputKeys.add(key)
153
- })
154
- })
155
- stream.on("error", (err: Error) => {
156
- reject(err)
157
- })
158
- stream.on("end", async () => {
159
- const keysArray: string[] = Array.from(outputKeys) as string[]
160
- try {
161
- let getPromises = []
162
- for (let key of keysArray) {
163
- getPromises.push(client.get(key))
164
- }
165
- const jsonArray = await Promise.all(getPromises)
166
- resolve(
167
- keysArray.map(key => ({
168
- key: removeDbPrefix(key),
169
- value: JSON.parse(jsonArray.shift()),
170
- }))
171
- )
172
- } catch (err) {
173
- reject(err)
174
- }
175
- })
176
- })
177
- }
178
-
179
- class RedisWrapper {
180
- _db: string
181
- _select: number
182
-
183
- constructor(db: string, selectDb: number | null = null) {
184
- this._db = db
185
- this._select = selectDb || DEFAULT_SELECT_DB
186
- }
187
-
188
- getClient() {
189
- return pickClient(this._select)
190
- }
191
-
192
- async init() {
193
- CLOSED = false
194
- init(this._select)
195
- await waitForConnection(this._select)
196
- if (this._select && !env.isTest()) {
197
- this.getClient().select(this._select)
198
- }
199
- return this
200
- }
201
-
202
- async finish() {
203
- CLOSED = true
204
- this.getClient().disconnect()
205
- }
206
-
207
- async scan(key = ""): Promise<any> {
208
- const db = this._db
209
- key = `${db}${SEPARATOR}${key}`
210
- let stream
211
- if (CLUSTERED) {
212
- let node = this.getClient().nodes("master")
213
- stream = node[0].scanStream({ match: key + "*", count: 100 })
214
- } else {
215
- stream = this.getClient().scanStream({ match: key + "*", count: 100 })
216
- }
217
- return promisifyStream(stream, this.getClient())
218
- }
219
-
220
- async keys(pattern: string) {
221
- const db = this._db
222
- return this.getClient().keys(addDbPrefix(db, pattern))
223
- }
224
-
225
- async exists(key: string) {
226
- const db = this._db
227
- return await this.getClient().exists(addDbPrefix(db, key))
228
- }
229
-
230
- async get(key: string) {
231
- const db = this._db
232
- let response = await this.getClient().get(addDbPrefix(db, key))
233
- // overwrite the prefixed key
234
- if (response != null && response.key) {
235
- response.key = key
236
- }
237
- // if its not an object just return the response
238
- try {
239
- return JSON.parse(response)
240
- } catch (err) {
241
- return response
242
- }
243
- }
244
-
245
- async bulkGet(keys: string[]) {
246
- const db = this._db
247
- if (keys.length === 0) {
248
- return {}
249
- }
250
- const prefixedKeys = keys.map(key => addDbPrefix(db, key))
251
- let response = await this.getClient().mget(prefixedKeys)
252
- if (Array.isArray(response)) {
253
- let final: any = {}
254
- let count = 0
255
- for (let result of response) {
256
- if (result) {
257
- let parsed
258
- try {
259
- parsed = JSON.parse(result)
260
- } catch (err) {
261
- parsed = result
262
- }
263
- final[keys[count]] = parsed
264
- }
265
- count++
266
- }
267
- return final
268
- } else {
269
- throw new Error(`Invalid response: ${response}`)
270
- }
271
- }
272
-
273
- async store(key: string, value: any, expirySeconds: number | null = null) {
274
- const db = this._db
275
- if (typeof value === "object") {
276
- value = JSON.stringify(value)
277
- }
278
- const prefixedKey = addDbPrefix(db, key)
279
- await this.getClient().set(prefixedKey, value)
280
- if (expirySeconds) {
281
- await this.getClient().expire(prefixedKey, expirySeconds)
282
- }
283
- }
284
-
285
- async getTTL(key: string) {
286
- const db = this._db
287
- const prefixedKey = addDbPrefix(db, key)
288
- return this.getClient().ttl(prefixedKey)
289
- }
290
-
291
- async setExpiry(key: string, expirySeconds: number | null) {
292
- const db = this._db
293
- const prefixedKey = addDbPrefix(db, key)
294
- await this.getClient().expire(prefixedKey, expirySeconds)
295
- }
296
-
297
- async delete(key: string) {
298
- const db = this._db
299
- await this.getClient().del(addDbPrefix(db, key))
300
- }
301
-
302
- async clear() {
303
- let items = await this.scan()
304
- await Promise.all(items.map((obj: any) => this.delete(obj.key)))
305
- }
306
- }
307
-
308
- export default RedisWrapper
@@ -1,139 +0,0 @@
1
- import Redlock from "redlock"
2
- import { getLockClient } from "./init"
3
- import { LockOptions, LockType } from "@budibase/types"
4
- import * as context from "../context"
5
- import env from "../environment"
6
-
7
- async function getClient(
8
- type: LockType,
9
- opts?: Redlock.Options
10
- ): Promise<Redlock> {
11
- if (type === LockType.CUSTOM) {
12
- return newRedlock(opts)
13
- }
14
- if (env.isTest() && type !== LockType.TRY_ONCE) {
15
- return newRedlock(OPTIONS.TEST)
16
- }
17
- switch (type) {
18
- case LockType.TRY_ONCE: {
19
- return newRedlock(OPTIONS.TRY_ONCE)
20
- }
21
- case LockType.TRY_TWICE: {
22
- return newRedlock(OPTIONS.TRY_TWICE)
23
- }
24
- case LockType.DEFAULT: {
25
- return newRedlock(OPTIONS.DEFAULT)
26
- }
27
- case LockType.DELAY_500: {
28
- return newRedlock(OPTIONS.DELAY_500)
29
- }
30
- default: {
31
- throw new Error(`Could not get redlock client: ${type}`)
32
- }
33
- }
34
- }
35
-
36
- const OPTIONS = {
37
- TRY_ONCE: {
38
- // immediately throws an error if the lock is already held
39
- retryCount: 0,
40
- },
41
- TRY_TWICE: {
42
- retryCount: 1,
43
- },
44
- TEST: {
45
- // higher retry count in unit tests
46
- // due to high contention.
47
- retryCount: 100,
48
- },
49
- DEFAULT: {
50
- // the expected clock drift; for more details
51
- // see http://redis.io/topics/distlock
52
- driftFactor: 0.01, // multiplied by lock ttl to determine drift time
53
-
54
- // the max number of times Redlock will attempt
55
- // to lock a resource before erroring
56
- retryCount: 10,
57
-
58
- // the time in ms between attempts
59
- retryDelay: 200, // time in ms
60
-
61
- // the max time in ms randomly added to retries
62
- // to improve performance under high contention
63
- // see https://www.awsarchitectureblog.com/2015/03/backoff.html
64
- retryJitter: 100, // time in ms
65
- },
66
- DELAY_500: {
67
- retryDelay: 500,
68
- },
69
- }
70
-
71
- export async function newRedlock(opts: Redlock.Options = {}) {
72
- let options = { ...OPTIONS.DEFAULT, ...opts }
73
- const redisWrapper = await getLockClient()
74
- const client = redisWrapper.getClient()
75
- return new Redlock([client], options)
76
- }
77
-
78
- type SuccessfulRedlockExecution<T> = {
79
- executed: true
80
- result: T
81
- }
82
- type UnsuccessfulRedlockExecution = {
83
- executed: false
84
- }
85
-
86
- type RedlockExecution<T> =
87
- | SuccessfulRedlockExecution<T>
88
- | UnsuccessfulRedlockExecution
89
-
90
- function getLockName(opts: LockOptions) {
91
- // determine lock name
92
- // by default use the tenantId for uniqueness, unless using a system lock
93
- const prefix = opts.systemLock ? "system" : context.getTenantId()
94
- let name: string = `lock:${prefix}_${opts.name}`
95
- // add additional unique name if required
96
- if (opts.resource) {
97
- name = name + `_${opts.resource}`
98
- }
99
- return name
100
- }
101
-
102
- export async function doWithLock<T>(
103
- opts: LockOptions,
104
- task: () => Promise<T>
105
- ): Promise<RedlockExecution<T>> {
106
- const redlock = await getClient(opts.type, opts.customOptions)
107
- let lock
108
- try {
109
- const name = getLockName(opts)
110
-
111
- // create the lock
112
- lock = await redlock.lock(name, opts.ttl)
113
-
114
- // perform locked task
115
- // need to await to ensure completion before unlocking
116
- const result = await task()
117
- return { executed: true, result }
118
- } catch (e: any) {
119
- console.warn("lock error")
120
- // lock limit exceeded
121
- if (e.name === "LockError") {
122
- if (opts.type === LockType.TRY_ONCE) {
123
- // don't throw for try-once locks, they will always error
124
- // due to retry count (0) exceeded
125
- return { executed: false }
126
- } else {
127
- console.error(e)
128
- throw e
129
- }
130
- } else {
131
- console.error(e)
132
- throw e
133
- }
134
- } finally {
135
- if (lock) {
136
- await lock.unlock()
137
- }
138
- }
139
- }
@@ -1,117 +0,0 @@
1
- import env from "../environment"
2
-
3
- const SLOT_REFRESH_MS = 2000
4
- const CONNECT_TIMEOUT_MS = 10000
5
- export const SEPARATOR = "-"
6
-
7
- /**
8
- * These Redis databases help us to segment up a Redis keyspace by prepending the
9
- * specified database name onto the cache key. This means that a single real Redis database
10
- * can be split up a bit; allowing us to use scans on small databases to find some particular
11
- * keys within.
12
- * If writing a very large volume of keys is expected (say 10K+) then it is better to keep these out
13
- * of the default keyspace and use a separate one - the SelectableDatabase can be used for this.
14
- */
15
- export enum Databases {
16
- PW_RESETS = "pwReset",
17
- VERIFICATIONS = "verification",
18
- INVITATIONS = "invitation",
19
- DEV_LOCKS = "devLocks",
20
- DEBOUNCE = "debounce",
21
- SESSIONS = "session",
22
- USER_CACHE = "users",
23
- FLAGS = "flags",
24
- APP_METADATA = "appMetadata",
25
- QUERY_VARS = "queryVars",
26
- LICENSES = "license",
27
- GENERIC_CACHE = "data_cache",
28
- WRITE_THROUGH = "writeThrough",
29
- LOCKS = "locks",
30
- SOCKET_IO = "socket_io",
31
- }
32
-
33
- /**
34
- * These define the numeric Redis databases that can be access with the SELECT command -
35
- * (https://redis.io/commands/select/). By default a Redis server/cluster will have 16 selectable
36
- * databases, increasing this count increases the amount of CPU/memory required to run the server.
37
- * Ideally new Redis keyspaces should be used sparingly, only when absolutely necessary for performance
38
- * to be maintained. Generally a keyspace can grow to be very large is scans are not needed or desired,
39
- * but if you need to walk through all values in a database periodically then a separate selectable
40
- * keyspace should be used.
41
- */
42
- export enum SelectableDatabase {
43
- DEFAULT = 0,
44
- SOCKET_IO = 1,
45
- UNUSED_1 = 2,
46
- UNUSED_2 = 3,
47
- UNUSED_3 = 4,
48
- UNUSED_4 = 5,
49
- UNUSED_5 = 6,
50
- UNUSED_6 = 7,
51
- UNUSED_7 = 8,
52
- UNUSED_8 = 9,
53
- UNUSED_9 = 10,
54
- UNUSED_10 = 11,
55
- UNUSED_11 = 12,
56
- UNUSED_12 = 13,
57
- UNUSED_13 = 14,
58
- UNUSED_14 = 15,
59
- }
60
-
61
- export function getRedisOptions() {
62
- let password = env.REDIS_PASSWORD
63
- let url: string[] | string = env.REDIS_URL.split("//")
64
- // get rid of the protocol
65
- url = url.length > 1 ? url[1] : url[0]
66
- // check for a password etc
67
- url = url.split("@")
68
- if (url.length > 1) {
69
- // get the password
70
- password = url[0].split(":")[1]
71
- url = url[1]
72
- } else {
73
- url = url[0]
74
- }
75
- const [host, port] = url.split(":")
76
-
77
- let redisProtocolUrl
78
-
79
- // fully qualified redis URL
80
- if (/rediss?:\/\//.test(env.REDIS_URL)) {
81
- redisProtocolUrl = env.REDIS_URL
82
- }
83
-
84
- const opts: any = {
85
- connectTimeout: CONNECT_TIMEOUT_MS,
86
- }
87
- if (env.REDIS_CLUSTERED) {
88
- opts.redisOptions = {}
89
- opts.redisOptions.tls = {}
90
- opts.redisOptions.password = password
91
- opts.slotsRefreshTimeout = SLOT_REFRESH_MS
92
- opts.dnsLookup = (address: string, callback: any) => callback(null, address)
93
- } else {
94
- opts.host = host
95
- opts.port = port
96
- opts.password = password
97
- }
98
- return { opts, host, port: parseInt(port), redisProtocolUrl }
99
- }
100
-
101
- export function addDbPrefix(db: string, key: string) {
102
- if (key.includes(db)) {
103
- return key
104
- }
105
- return `${db}${SEPARATOR}${key}`
106
- }
107
-
108
- export function removeDbPrefix(key: string) {
109
- let parts = key.split(SEPARATOR)
110
- if (parts.length >= 2) {
111
- parts.shift()
112
- return parts.join(SEPARATOR)
113
- } else {
114
- // return the only part
115
- return parts[0]
116
- }
117
- }