@budibase/backend-core 2.9.40-alpha.6 → 2.10.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 (252) hide show
  1. package/dist/index.js +5 -4
  2. package/dist/index.js.map +2 -2
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +6 -6
  5. package/dist/src/cache/appMetadata.js +1 -1
  6. package/dist/src/cache/appMetadata.js.map +1 -1
  7. package/dist/src/constants/misc.d.ts +0 -2
  8. package/dist/src/constants/misc.js +0 -2
  9. package/dist/src/constants/misc.js.map +1 -1
  10. package/dist/src/environment.js +5 -4
  11. package/dist/src/environment.js.map +1 -1
  12. package/dist/src/logging/system.d.ts +1 -1
  13. package/dist/src/timers/timers.d.ts +1 -1
  14. package/package.json +6 -6
  15. package/src/accounts/accounts.ts +82 -0
  16. package/src/accounts/api.ts +59 -0
  17. package/src/accounts/index.ts +1 -0
  18. package/src/auth/auth.ts +208 -0
  19. package/src/auth/index.ts +1 -0
  20. package/src/auth/tests/auth.spec.ts +14 -0
  21. package/src/blacklist/blacklist.ts +54 -0
  22. package/src/blacklist/index.ts +1 -0
  23. package/src/blacklist/tests/blacklist.spec.ts +46 -0
  24. package/src/cache/appMetadata.ts +88 -0
  25. package/src/cache/base/index.ts +92 -0
  26. package/src/cache/generic.ts +30 -0
  27. package/src/cache/index.ts +5 -0
  28. package/src/cache/tests/writethrough.spec.ts +138 -0
  29. package/src/cache/user.ts +83 -0
  30. package/src/cache/writethrough.ts +133 -0
  31. package/src/configs/configs.ts +257 -0
  32. package/src/configs/index.ts +1 -0
  33. package/src/configs/tests/configs.spec.ts +184 -0
  34. package/src/constants/db.ts +63 -0
  35. package/src/constants/index.ts +2 -0
  36. package/src/constants/misc.ts +50 -0
  37. package/src/context/Context.ts +14 -0
  38. package/src/context/identity.ts +58 -0
  39. package/src/context/index.ts +3 -0
  40. package/src/context/mainContext.ts +310 -0
  41. package/src/context/tests/index.spec.ts +147 -0
  42. package/src/context/types.ts +11 -0
  43. package/src/db/Replication.ts +84 -0
  44. package/src/db/constants.ts +10 -0
  45. package/src/db/couch/DatabaseImpl.ts +238 -0
  46. package/src/db/couch/connections.ts +77 -0
  47. package/src/db/couch/index.ts +5 -0
  48. package/src/db/couch/pouchDB.ts +97 -0
  49. package/src/db/couch/pouchDump.ts +0 -0
  50. package/src/db/couch/utils.ts +50 -0
  51. package/src/db/db.ts +43 -0
  52. package/src/db/errors.ts +14 -0
  53. package/src/db/index.ts +12 -0
  54. package/src/db/lucene.ts +750 -0
  55. package/src/db/searchIndexes/index.ts +1 -0
  56. package/src/db/searchIndexes/searchIndexes.ts +62 -0
  57. package/src/db/tests/index.spec.js +25 -0
  58. package/src/db/tests/lucene.spec.ts +368 -0
  59. package/src/db/tests/pouch.spec.js +62 -0
  60. package/src/db/tests/utils.spec.ts +63 -0
  61. package/src/db/utils.ts +207 -0
  62. package/src/db/views.ts +241 -0
  63. package/src/docIds/conversions.ts +59 -0
  64. package/src/docIds/ids.ts +113 -0
  65. package/src/docIds/index.ts +2 -0
  66. package/src/docIds/newid.ts +5 -0
  67. package/src/docIds/params.ts +174 -0
  68. package/src/docUpdates/index.ts +29 -0
  69. package/src/environment.ts +201 -0
  70. package/src/errors/errors.ts +119 -0
  71. package/src/errors/index.ts +1 -0
  72. package/src/events/analytics.ts +6 -0
  73. package/src/events/asyncEvents/index.ts +2 -0
  74. package/src/events/asyncEvents/publisher.ts +12 -0
  75. package/src/events/asyncEvents/queue.ts +22 -0
  76. package/src/events/backfill.ts +183 -0
  77. package/src/events/documentId.ts +56 -0
  78. package/src/events/events.ts +40 -0
  79. package/src/events/identification.ts +310 -0
  80. package/src/events/index.ts +14 -0
  81. package/src/events/processors/AnalyticsProcessor.ts +64 -0
  82. package/src/events/processors/AuditLogsProcessor.ts +93 -0
  83. package/src/events/processors/LoggingProcessor.ts +37 -0
  84. package/src/events/processors/Processors.ts +52 -0
  85. package/src/events/processors/async/DocumentUpdateProcessor.ts +43 -0
  86. package/src/events/processors/index.ts +19 -0
  87. package/src/events/processors/posthog/PosthogProcessor.ts +118 -0
  88. package/src/events/processors/posthog/index.ts +2 -0
  89. package/src/events/processors/posthog/rateLimiting.ts +106 -0
  90. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +168 -0
  91. package/src/events/processors/types.ts +1 -0
  92. package/src/events/publishers/account.ts +35 -0
  93. package/src/events/publishers/app.ts +155 -0
  94. package/src/events/publishers/auditLog.ts +26 -0
  95. package/src/events/publishers/auth.ts +73 -0
  96. package/src/events/publishers/automation.ts +110 -0
  97. package/src/events/publishers/backfill.ts +74 -0
  98. package/src/events/publishers/backup.ts +42 -0
  99. package/src/events/publishers/datasource.ts +48 -0
  100. package/src/events/publishers/email.ts +17 -0
  101. package/src/events/publishers/environmentVariable.ts +38 -0
  102. package/src/events/publishers/group.ts +99 -0
  103. package/src/events/publishers/index.ts +24 -0
  104. package/src/events/publishers/installation.ts +38 -0
  105. package/src/events/publishers/layout.ts +26 -0
  106. package/src/events/publishers/license.ts +84 -0
  107. package/src/events/publishers/org.ts +37 -0
  108. package/src/events/publishers/plugin.ts +47 -0
  109. package/src/events/publishers/query.ts +88 -0
  110. package/src/events/publishers/role.ts +62 -0
  111. package/src/events/publishers/rows.ts +29 -0
  112. package/src/events/publishers/screen.ts +36 -0
  113. package/src/events/publishers/serve.ts +43 -0
  114. package/src/events/publishers/table.ts +70 -0
  115. package/src/events/publishers/user.ts +202 -0
  116. package/src/events/publishers/view.ts +107 -0
  117. package/src/features/index.ts +78 -0
  118. package/src/features/installation.ts +17 -0
  119. package/src/features/tests/featureFlags.spec.ts +85 -0
  120. package/src/helpers.ts +9 -0
  121. package/src/index.ts +54 -0
  122. package/src/installation.ts +107 -0
  123. package/src/logging/alerts.ts +26 -0
  124. package/src/logging/correlation/correlation.ts +13 -0
  125. package/src/logging/correlation/index.ts +1 -0
  126. package/src/logging/correlation/middleware.ts +17 -0
  127. package/src/logging/index.ts +4 -0
  128. package/src/logging/pino/logger.ts +232 -0
  129. package/src/logging/pino/middleware.ts +45 -0
  130. package/src/logging/system.ts +81 -0
  131. package/src/logging/tests/system.spec.ts +61 -0
  132. package/src/middleware/adminOnly.ts +9 -0
  133. package/src/middleware/auditLog.ts +6 -0
  134. package/src/middleware/authenticated.ts +193 -0
  135. package/src/middleware/builderOnly.ts +21 -0
  136. package/src/middleware/builderOrAdmin.ts +21 -0
  137. package/src/middleware/csrf.ts +81 -0
  138. package/src/middleware/errorHandling.ts +29 -0
  139. package/src/middleware/index.ts +21 -0
  140. package/src/middleware/internalApi.ts +23 -0
  141. package/src/middleware/joi-validator.ts +45 -0
  142. package/src/middleware/matchers.ts +47 -0
  143. package/src/middleware/passport/datasource/google.ts +95 -0
  144. package/src/middleware/passport/local.ts +54 -0
  145. package/src/middleware/passport/sso/google.ts +77 -0
  146. package/src/middleware/passport/sso/oidc.ts +154 -0
  147. package/src/middleware/passport/sso/sso.ts +165 -0
  148. package/src/middleware/passport/sso/tests/google.spec.ts +67 -0
  149. package/src/middleware/passport/sso/tests/oidc.spec.ts +152 -0
  150. package/src/middleware/passport/sso/tests/sso.spec.ts +197 -0
  151. package/src/middleware/passport/utils.ts +38 -0
  152. package/src/middleware/querystringToBody.ts +28 -0
  153. package/src/middleware/tenancy.ts +36 -0
  154. package/src/middleware/tests/builder.spec.ts +180 -0
  155. package/src/middleware/tests/matchers.spec.ts +134 -0
  156. package/src/migrations/definitions.ts +40 -0
  157. package/src/migrations/index.ts +2 -0
  158. package/src/migrations/migrations.ts +191 -0
  159. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +11 -0
  160. package/src/migrations/tests/migrations.spec.ts +64 -0
  161. package/src/objectStore/buckets/app.ts +40 -0
  162. package/src/objectStore/buckets/global.ts +29 -0
  163. package/src/objectStore/buckets/index.ts +3 -0
  164. package/src/objectStore/buckets/plugins.ts +71 -0
  165. package/src/objectStore/buckets/tests/app.spec.ts +171 -0
  166. package/src/objectStore/buckets/tests/global.spec.ts +74 -0
  167. package/src/objectStore/buckets/tests/plugins.spec.ts +111 -0
  168. package/src/objectStore/cloudfront.ts +41 -0
  169. package/src/objectStore/index.ts +3 -0
  170. package/src/objectStore/objectStore.ts +440 -0
  171. package/src/objectStore/utils.ts +27 -0
  172. package/src/platform/index.ts +3 -0
  173. package/src/platform/platformDb.ts +6 -0
  174. package/src/platform/tenants.ts +101 -0
  175. package/src/platform/tests/tenants.spec.ts +26 -0
  176. package/src/platform/users.ts +90 -0
  177. package/src/plugin/index.ts +1 -0
  178. package/src/plugin/tests/validation.spec.ts +83 -0
  179. package/src/plugin/utils.ts +156 -0
  180. package/src/queue/constants.ts +6 -0
  181. package/src/queue/inMemoryQueue.ts +141 -0
  182. package/src/queue/index.ts +2 -0
  183. package/src/queue/listeners.ts +195 -0
  184. package/src/queue/queue.ts +54 -0
  185. package/src/redis/index.ts +6 -0
  186. package/src/redis/init.ts +86 -0
  187. package/src/redis/redis.ts +308 -0
  188. package/src/redis/redlockImpl.ts +139 -0
  189. package/src/redis/utils.ts +117 -0
  190. package/src/security/encryption.ts +179 -0
  191. package/src/security/permissions.ts +158 -0
  192. package/src/security/roles.ts +389 -0
  193. package/src/security/sessions.ts +120 -0
  194. package/src/security/tests/encryption.spec.ts +31 -0
  195. package/src/security/tests/permissions.spec.ts +145 -0
  196. package/src/security/tests/sessions.spec.ts +12 -0
  197. package/src/tenancy/db.ts +6 -0
  198. package/src/tenancy/index.ts +2 -0
  199. package/src/tenancy/tenancy.ts +140 -0
  200. package/src/tenancy/tests/tenancy.spec.ts +184 -0
  201. package/src/timers/index.ts +1 -0
  202. package/src/timers/timers.ts +22 -0
  203. package/src/users/db.ts +484 -0
  204. package/src/users/events.ts +176 -0
  205. package/src/users/index.ts +4 -0
  206. package/src/users/lookup.ts +102 -0
  207. package/src/users/users.ts +276 -0
  208. package/src/users/utils.ts +55 -0
  209. package/src/utils/hashing.ts +14 -0
  210. package/src/utils/index.ts +3 -0
  211. package/src/utils/stringUtils.ts +8 -0
  212. package/src/utils/tests/utils.spec.ts +191 -0
  213. package/src/utils/utils.ts +239 -0
  214. package/tests/core/logging.ts +34 -0
  215. package/tests/core/utilities/index.ts +6 -0
  216. package/tests/core/utilities/jestUtils.ts +30 -0
  217. package/tests/core/utilities/mocks/alerts.ts +3 -0
  218. package/tests/core/utilities/mocks/date.ts +2 -0
  219. package/tests/core/utilities/mocks/events.ts +131 -0
  220. package/tests/core/utilities/mocks/fetch.ts +17 -0
  221. package/tests/core/utilities/mocks/index.ts +10 -0
  222. package/tests/core/utilities/mocks/licenses.ts +115 -0
  223. package/tests/core/utilities/mocks/posthog.ts +7 -0
  224. package/tests/core/utilities/structures/Chance.ts +20 -0
  225. package/tests/core/utilities/structures/accounts.ts +115 -0
  226. package/tests/core/utilities/structures/apps.ts +21 -0
  227. package/tests/core/utilities/structures/common.ts +7 -0
  228. package/tests/core/utilities/structures/db.ts +12 -0
  229. package/tests/core/utilities/structures/documents/index.ts +1 -0
  230. package/tests/core/utilities/structures/documents/platform/index.ts +1 -0
  231. package/tests/core/utilities/structures/documents/platform/installation.ts +12 -0
  232. package/tests/core/utilities/structures/generator.ts +2 -0
  233. package/tests/core/utilities/structures/index.ts +15 -0
  234. package/tests/core/utilities/structures/koa.ts +16 -0
  235. package/tests/core/utilities/structures/licenses.ts +167 -0
  236. package/tests/core/utilities/structures/plugins.ts +19 -0
  237. package/tests/core/utilities/structures/quotas.ts +67 -0
  238. package/tests/core/utilities/structures/scim.ts +80 -0
  239. package/tests/core/utilities/structures/shared.ts +19 -0
  240. package/tests/core/utilities/structures/sso.ts +119 -0
  241. package/tests/core/utilities/structures/tenants.ts +5 -0
  242. package/tests/core/utilities/structures/userGroups.ts +10 -0
  243. package/tests/core/utilities/structures/users.ts +73 -0
  244. package/tests/core/utilities/testContainerUtils.ts +85 -0
  245. package/tests/core/utilities/utils/index.ts +1 -0
  246. package/tests/core/utilities/utils/time.ts +3 -0
  247. package/tests/extra/DBTestConfiguration.ts +36 -0
  248. package/tests/extra/index.ts +2 -0
  249. package/tests/extra/testEnv.ts +95 -0
  250. package/tests/index.ts +1 -0
  251. package/tests/jestEnv.ts +6 -0
  252. package/tests/jestSetup.ts +28 -0
@@ -0,0 +1,310 @@
1
+ // some test cases call functions directly, need to
2
+ // store an app ID to pretend there is a context
3
+ import env from "../environment"
4
+ import Context from "./Context"
5
+ import * as conversions from "../docIds/conversions"
6
+ import { getDB } from "../db/db"
7
+ import {
8
+ DocumentType,
9
+ SEPARATOR,
10
+ StaticDatabases,
11
+ DEFAULT_TENANT_ID,
12
+ } from "../constants"
13
+ import { Database, IdentityContext } from "@budibase/types"
14
+ import { ContextMap } from "./types"
15
+
16
+ let TEST_APP_ID: string | null = null
17
+
18
+ export function getGlobalDBName(tenantId?: string) {
19
+ // tenant ID can be set externally, for example user API where
20
+ // new tenants are being created, this may be the case
21
+ if (!tenantId) {
22
+ tenantId = getTenantId()
23
+ }
24
+ return baseGlobalDBName(tenantId)
25
+ }
26
+
27
+ export function getAuditLogDBName(tenantId?: string) {
28
+ if (!tenantId) {
29
+ tenantId = getTenantId()
30
+ }
31
+ if (tenantId === DEFAULT_TENANT_ID) {
32
+ return StaticDatabases.AUDIT_LOGS.name
33
+ } else {
34
+ return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}`
35
+ }
36
+ }
37
+
38
+ export function baseGlobalDBName(tenantId: string | undefined | null) {
39
+ if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
40
+ return StaticDatabases.GLOBAL.name
41
+ } else {
42
+ return `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}`
43
+ }
44
+ }
45
+
46
+ export function getPlatformURL() {
47
+ return env.PLATFORM_URL
48
+ }
49
+
50
+ export function isMultiTenant() {
51
+ return !!env.MULTI_TENANCY
52
+ }
53
+
54
+ export function isTenantIdSet() {
55
+ const context = Context.get()
56
+ return !!context?.tenantId
57
+ }
58
+
59
+ export function isTenancyEnabled() {
60
+ return env.MULTI_TENANCY
61
+ }
62
+
63
+ /**
64
+ * Given an app ID this will attempt to retrieve the tenant ID from it.
65
+ * @return {null|string} The tenant ID found within the app ID.
66
+ */
67
+ export function getTenantIDFromAppID(appId: string) {
68
+ if (!appId) {
69
+ return undefined
70
+ }
71
+ if (!isMultiTenant()) {
72
+ return DEFAULT_TENANT_ID
73
+ }
74
+ const split = appId.split(SEPARATOR)
75
+ const hasDev = split[1] === DocumentType.DEV
76
+ if ((hasDev && split.length === 3) || (!hasDev && split.length === 2)) {
77
+ return undefined
78
+ }
79
+ if (hasDev) {
80
+ return split[2]
81
+ } else {
82
+ return split[1]
83
+ }
84
+ }
85
+
86
+ function updateContext(updates: ContextMap): ContextMap {
87
+ let context: ContextMap
88
+ try {
89
+ context = Context.get()
90
+ } catch (err) {
91
+ // no context, start empty
92
+ context = {}
93
+ }
94
+ context = {
95
+ ...context,
96
+ ...updates,
97
+ }
98
+ return context
99
+ }
100
+
101
+ async function newContext(updates: ContextMap, task: any) {
102
+ // see if there already is a context setup
103
+ let context: ContextMap = updateContext(updates)
104
+ return Context.run(context, task)
105
+ }
106
+
107
+ export async function doInAutomationContext(params: {
108
+ appId: string
109
+ automationId: string
110
+ task: any
111
+ }): Promise<any> {
112
+ const tenantId = getTenantIDFromAppID(params.appId)
113
+ return newContext(
114
+ {
115
+ tenantId,
116
+ appId: params.appId,
117
+ automationId: params.automationId,
118
+ },
119
+ params.task
120
+ )
121
+ }
122
+
123
+ export async function doInContext(appId: string, task: any): Promise<any> {
124
+ const tenantId = getTenantIDFromAppID(appId)
125
+ return newContext(
126
+ {
127
+ tenantId,
128
+ appId,
129
+ },
130
+ task
131
+ )
132
+ }
133
+
134
+ export async function doInTenant<T>(
135
+ tenantId: string | null,
136
+ task: () => T
137
+ ): Promise<T> {
138
+ // make sure default always selected in single tenancy
139
+ if (!env.MULTI_TENANCY) {
140
+ tenantId = tenantId || DEFAULT_TENANT_ID
141
+ }
142
+
143
+ const updates = tenantId ? { tenantId } : {}
144
+ return newContext(updates, task)
145
+ }
146
+
147
+ export async function doInAppContext(
148
+ appId: string | null,
149
+ task: any
150
+ ): Promise<any> {
151
+ if (!appId && !env.isTest()) {
152
+ throw new Error("appId is required")
153
+ }
154
+
155
+ let updates: ContextMap
156
+ if (!appId) {
157
+ updates = { appId: "" }
158
+ } else {
159
+ const tenantId = getTenantIDFromAppID(appId)
160
+ updates = { appId }
161
+ if (tenantId) {
162
+ updates.tenantId = tenantId
163
+ }
164
+ }
165
+ return newContext(updates, task)
166
+ }
167
+
168
+ export async function doInIdentityContext(
169
+ identity: IdentityContext,
170
+ task: any
171
+ ): Promise<any> {
172
+ if (!identity) {
173
+ throw new Error("identity is required")
174
+ }
175
+
176
+ const context: ContextMap = {
177
+ identity,
178
+ }
179
+ if (identity.tenantId) {
180
+ context.tenantId = identity.tenantId
181
+ }
182
+ return newContext(context, task)
183
+ }
184
+
185
+ export function getIdentity(): IdentityContext | undefined {
186
+ try {
187
+ const context = Context.get()
188
+ return context?.identity
189
+ } catch (e) {
190
+ // do nothing - identity is not in context
191
+ }
192
+ }
193
+
194
+ export function getTenantId(): string {
195
+ if (!isMultiTenant()) {
196
+ return DEFAULT_TENANT_ID
197
+ }
198
+ const context = Context.get()
199
+ const tenantId = context?.tenantId
200
+ if (!tenantId) {
201
+ throw new Error("Tenant id not found")
202
+ }
203
+ return tenantId
204
+ }
205
+
206
+ export function getAutomationId(): string | undefined {
207
+ const context = Context.get()
208
+ return context?.automationId
209
+ }
210
+
211
+ export function getAppId(): string | undefined {
212
+ const context = Context.get()
213
+ const foundId = context?.appId
214
+ if (!foundId && env.isTest() && TEST_APP_ID) {
215
+ return TEST_APP_ID
216
+ } else {
217
+ return foundId
218
+ }
219
+ }
220
+
221
+ export const getProdAppId = () => {
222
+ const appId = getAppId()
223
+ if (!appId) {
224
+ throw new Error("Could not get appId")
225
+ }
226
+ return conversions.getProdAppID(appId)
227
+ }
228
+
229
+ export function doInEnvironmentContext(
230
+ values: Record<string, string>,
231
+ task: any
232
+ ) {
233
+ if (!values) {
234
+ throw new Error("Must supply environment variables.")
235
+ }
236
+ const updates = {
237
+ environmentVariables: values,
238
+ }
239
+ return newContext(updates, task)
240
+ }
241
+
242
+ export function doInScimContext(task: any) {
243
+ const updates: ContextMap = {
244
+ isScim: true,
245
+ }
246
+ return newContext(updates, task)
247
+ }
248
+
249
+ export function getEnvironmentVariables() {
250
+ const context = Context.get()
251
+ if (!context.environmentVariables) {
252
+ return null
253
+ } else {
254
+ return context.environmentVariables
255
+ }
256
+ }
257
+
258
+ export function getGlobalDB(): Database {
259
+ const context = Context.get()
260
+ if (!context || (env.MULTI_TENANCY && !context.tenantId)) {
261
+ throw new Error("Global DB not found")
262
+ }
263
+ return getDB(baseGlobalDBName(context?.tenantId))
264
+ }
265
+
266
+ export function getAuditLogsDB(): Database {
267
+ if (!getTenantId()) {
268
+ throw new Error("No tenant ID found - cannot open audit log DB")
269
+ }
270
+ return getDB(getAuditLogDBName())
271
+ }
272
+
273
+ /**
274
+ * Gets the app database based on whatever the request
275
+ * contained, dev or prod.
276
+ */
277
+ export function getAppDB(opts?: any): Database {
278
+ const appId = getAppId()
279
+ return getDB(appId, opts)
280
+ }
281
+
282
+ /**
283
+ * This specifically gets the prod app ID, if the request
284
+ * contained a development app ID, this will get the prod one.
285
+ */
286
+ export function getProdAppDB(opts?: any): Database {
287
+ const appId = getAppId()
288
+ if (!appId) {
289
+ throw new Error("Unable to retrieve prod DB - no app ID.")
290
+ }
291
+ return getDB(conversions.getProdAppID(appId), opts)
292
+ }
293
+
294
+ /**
295
+ * This specifically gets the dev app ID, if the request
296
+ * contained a prod app ID, this will get the dev one.
297
+ */
298
+ export function getDevAppDB(opts?: any): Database {
299
+ const appId = getAppId()
300
+ if (!appId) {
301
+ throw new Error("Unable to retrieve dev DB - no app ID.")
302
+ }
303
+ return getDB(conversions.getDevelopmentAppID(appId), opts)
304
+ }
305
+
306
+ export function isScim(): boolean {
307
+ const context = Context.get()
308
+ const scimCall = context?.isScim
309
+ return !!scimCall
310
+ }
@@ -0,0 +1,147 @@
1
+ import { testEnv } from "../../../tests/extra"
2
+ import * as context from "../"
3
+ import { DEFAULT_TENANT_ID } from "../../constants"
4
+
5
+ describe("context", () => {
6
+ describe("doInTenant", () => {
7
+ describe("single-tenancy", () => {
8
+ beforeAll(() => {
9
+ testEnv.singleTenant()
10
+ })
11
+
12
+ it("defaults to the default tenant", () => {
13
+ const tenantId = context.getTenantId()
14
+ expect(tenantId).toBe(DEFAULT_TENANT_ID)
15
+ })
16
+
17
+ it("defaults to the default tenant db", async () => {
18
+ await context.doInTenant(DEFAULT_TENANT_ID, () => {
19
+ const db = context.getGlobalDB()
20
+ expect(db.name).toBe("global-db")
21
+ })
22
+ })
23
+ })
24
+
25
+ describe("multi-tenancy", () => {
26
+ beforeAll(() => {
27
+ testEnv.multiTenant()
28
+ })
29
+
30
+ it("fails when no tenant id is set", () => {
31
+ const test = () => {
32
+ let error: any
33
+ try {
34
+ context.getTenantId()
35
+ } catch (e) {
36
+ error = e
37
+ }
38
+ expect(error.message).toBe("Tenant id not found")
39
+ }
40
+
41
+ // test under no tenancy
42
+ test()
43
+
44
+ // test after tenancy has been accessed to ensure cleanup
45
+ context.doInTenant("test", () => {})
46
+ test()
47
+ })
48
+
49
+ it("fails when no tenant db is set", () => {
50
+ const test = () => {
51
+ let error: any
52
+ try {
53
+ context.getGlobalDB()
54
+ } catch (e) {
55
+ error = e
56
+ }
57
+ expect(error.message).toBe("Global DB not found")
58
+ }
59
+
60
+ // test under no tenancy
61
+ test()
62
+
63
+ // test after tenancy has been accessed to ensure cleanup
64
+ context.doInTenant("test", () => {})
65
+ test()
66
+ })
67
+
68
+ it("sets tenant id", () => {
69
+ context.doInTenant("test", () => {
70
+ const tenantId = context.getTenantId()
71
+ expect(tenantId).toBe("test")
72
+ })
73
+ })
74
+
75
+ it("initialises the tenant db", async () => {
76
+ await context.doInTenant("test", () => {
77
+ const db = context.getGlobalDB()
78
+ expect(db.name).toBe("test_global-db")
79
+ })
80
+ })
81
+
82
+ it("sets the tenant id when nested with same tenant id", async () => {
83
+ await context.doInTenant("test", async () => {
84
+ const tenantId = context.getTenantId()
85
+ expect(tenantId).toBe("test")
86
+
87
+ await context.doInTenant("test", async () => {
88
+ const tenantId = context.getTenantId()
89
+ expect(tenantId).toBe("test")
90
+
91
+ await context.doInTenant("test", () => {
92
+ const tenantId = context.getTenantId()
93
+ expect(tenantId).toBe("test")
94
+ })
95
+ })
96
+ })
97
+ })
98
+
99
+ it("initialises the tenant db when nested with same tenant id", async () => {
100
+ await context.doInTenant("test", async () => {
101
+ const db = context.getGlobalDB()
102
+ expect(db.name).toBe("test_global-db")
103
+
104
+ await context.doInTenant("test", async () => {
105
+ const db = context.getGlobalDB()
106
+ expect(db.name).toBe("test_global-db")
107
+
108
+ await context.doInTenant("test", () => {
109
+ const db = context.getGlobalDB()
110
+ expect(db.name).toBe("test_global-db")
111
+ })
112
+ })
113
+ })
114
+ })
115
+
116
+ it("sets different tenant id inside another context", () => {
117
+ context.doInTenant("test", () => {
118
+ const tenantId = context.getTenantId()
119
+ expect(tenantId).toBe("test")
120
+
121
+ context.doInTenant("nested", () => {
122
+ const tenantId = context.getTenantId()
123
+ expect(tenantId).toBe("nested")
124
+
125
+ context.doInTenant("double-nested", () => {
126
+ const tenantId = context.getTenantId()
127
+ expect(tenantId).toBe("double-nested")
128
+ })
129
+ })
130
+ })
131
+ })
132
+ })
133
+ })
134
+
135
+ describe("doInScimContext", () => {
136
+ it("returns true when set", () => {
137
+ context.doInScimContext(() => {
138
+ const isScim = context.isScim()
139
+ expect(isScim).toBe(true)
140
+ })
141
+ })
142
+ it("returns false when not set", () => {
143
+ const isScim = context.isScim()
144
+ expect(isScim).toBe(false)
145
+ })
146
+ })
147
+ })
@@ -0,0 +1,11 @@
1
+ import { IdentityContext } from "@budibase/types"
2
+
3
+ // keep this out of Budibase types, don't want to expose context info
4
+ export type ContextMap = {
5
+ tenantId?: string
6
+ appId?: string
7
+ identity?: IdentityContext
8
+ environmentVariables?: Record<string, string>
9
+ isScim?: boolean
10
+ automationId?: string
11
+ }
@@ -0,0 +1,84 @@
1
+ import { getPouchDB, closePouchDB } from "./couch"
2
+ import { DocumentType } from "../constants"
3
+
4
+ class Replication {
5
+ source: any
6
+ target: any
7
+ replication: any
8
+
9
+ /**
10
+ *
11
+ * @param {String} source - the DB you want to replicate or rollback to
12
+ * @param {String} target - the DB you want to replicate to, or rollback from
13
+ */
14
+ constructor({ source, target }: any) {
15
+ this.source = getPouchDB(source)
16
+ this.target = getPouchDB(target)
17
+ }
18
+
19
+ close() {
20
+ return Promise.all([closePouchDB(this.source), closePouchDB(this.target)])
21
+ }
22
+
23
+ promisify(operation: any, opts = {}) {
24
+ return new Promise(resolve => {
25
+ operation(this.target, opts)
26
+ .on("denied", function (err: any) {
27
+ // a document failed to replicate (e.g. due to permissions)
28
+ throw new Error(`Denied: Document failed to replicate ${err}`)
29
+ })
30
+ .on("complete", function (info: any) {
31
+ return resolve(info)
32
+ })
33
+ .on("error", function (err: any) {
34
+ throw new Error(`Replication Error: ${err}`)
35
+ })
36
+ })
37
+ }
38
+
39
+ /**
40
+ * Two way replication operation, intended to be promise based.
41
+ * @param {Object} opts - PouchDB replication options
42
+ */
43
+ sync(opts = {}) {
44
+ this.replication = this.promisify(this.source.sync, opts)
45
+ return this.replication
46
+ }
47
+
48
+ /**
49
+ * One way replication operation, intended to be promise based.
50
+ * @param {Object} opts - PouchDB replication options
51
+ */
52
+ replicate(opts = {}) {
53
+ this.replication = this.promisify(this.source.replicate.to, opts)
54
+ return this.replication
55
+ }
56
+
57
+ appReplicateOpts() {
58
+ return {
59
+ filter: (doc: any) => {
60
+ if (doc._id && doc._id.startsWith(DocumentType.AUTOMATION_LOG)) {
61
+ return false
62
+ }
63
+ return doc._id !== DocumentType.APP_METADATA
64
+ },
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Rollback the target DB back to the state of the source DB
70
+ */
71
+ async rollback() {
72
+ await this.target.destroy()
73
+ // Recreate the DB again
74
+ this.target = getPouchDB(this.target.name)
75
+ // take the opportunity to remove deleted tombstones
76
+ await this.replicate()
77
+ }
78
+
79
+ cancel() {
80
+ this.replication.cancel()
81
+ }
82
+ }
83
+
84
+ export default Replication
@@ -0,0 +1,10 @@
1
+ export const CONSTANT_INTERNAL_ROW_COLS = [
2
+ "_id",
3
+ "_rev",
4
+ "type",
5
+ "createdAt",
6
+ "updatedAt",
7
+ "tableId",
8
+ ] as const
9
+
10
+ export const CONSTANT_EXTERNAL_ROW_COLS = ["_id", "_rev", "tableId"] as const