@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.
- package/dist/index.js +324 -266
- package/dist/index.js.map +4 -4
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +19 -4
- package/dist/plugins.js +1 -1
- package/dist/plugins.js.map +1 -1
- package/dist/plugins.js.meta.json +1 -1
- package/dist/src/security/permissions.d.ts +1 -1
- package/dist/tests.js +260 -222
- package/dist/tests.js.map +4 -4
- package/dist/tests.js.meta.json +1 -1
- package/package.json +19 -4
- package/__mocks__/aws-sdk.ts +0 -18
- package/dist/tsconfig.build.tsbuildinfo +0 -1
- package/jest-testcontainers-config.js +0 -8
- package/jest.config.ts +0 -35
- package/scripts/build.js +0 -6
- package/scripts/test.sh +0 -13
- package/src/accounts/accounts.ts +0 -82
- package/src/accounts/api.ts +0 -59
- package/src/accounts/index.ts +0 -1
- package/src/auth/auth.ts +0 -208
- package/src/auth/index.ts +0 -1
- package/src/auth/tests/auth.spec.ts +0 -14
- package/src/blacklist/blacklist.ts +0 -54
- package/src/blacklist/index.ts +0 -1
- package/src/blacklist/tests/blacklist.spec.ts +0 -46
- package/src/cache/appMetadata.ts +0 -88
- package/src/cache/base/index.ts +0 -92
- package/src/cache/generic.ts +0 -30
- package/src/cache/index.ts +0 -5
- package/src/cache/tests/writethrough.spec.ts +0 -138
- package/src/cache/user.ts +0 -69
- package/src/cache/writethrough.ts +0 -133
- package/src/configs/configs.ts +0 -257
- package/src/configs/index.ts +0 -1
- package/src/configs/tests/configs.spec.ts +0 -184
- package/src/constants/db.ts +0 -63
- package/src/constants/index.ts +0 -2
- package/src/constants/misc.ts +0 -50
- package/src/context/Context.ts +0 -14
- package/src/context/identity.ts +0 -58
- package/src/context/index.ts +0 -3
- package/src/context/mainContext.ts +0 -310
- package/src/context/tests/index.spec.ts +0 -147
- package/src/context/types.ts +0 -11
- package/src/db/Replication.ts +0 -84
- package/src/db/constants.ts +0 -10
- package/src/db/couch/DatabaseImpl.ts +0 -238
- package/src/db/couch/connections.ts +0 -77
- package/src/db/couch/index.ts +0 -5
- package/src/db/couch/pouchDB.ts +0 -97
- package/src/db/couch/pouchDump.ts +0 -0
- package/src/db/couch/utils.ts +0 -50
- package/src/db/db.ts +0 -39
- package/src/db/errors.ts +0 -14
- package/src/db/index.ts +0 -12
- package/src/db/lucene.ts +0 -732
- package/src/db/searchIndexes/index.ts +0 -1
- package/src/db/searchIndexes/searchIndexes.ts +0 -62
- package/src/db/tests/index.spec.js +0 -25
- package/src/db/tests/lucene.spec.ts +0 -298
- package/src/db/tests/pouch.spec.js +0 -62
- package/src/db/tests/utils.spec.ts +0 -63
- package/src/db/utils.ts +0 -207
- package/src/db/views.ts +0 -241
- package/src/docIds/conversions.ts +0 -59
- package/src/docIds/ids.ts +0 -113
- package/src/docIds/index.ts +0 -2
- package/src/docIds/newid.ts +0 -5
- package/src/docIds/params.ts +0 -174
- package/src/docUpdates/index.ts +0 -29
- package/src/environment.ts +0 -201
- package/src/errors/errors.ts +0 -119
- package/src/errors/index.ts +0 -1
- package/src/events/analytics.ts +0 -6
- package/src/events/asyncEvents/index.ts +0 -2
- package/src/events/asyncEvents/publisher.ts +0 -12
- package/src/events/asyncEvents/queue.ts +0 -22
- package/src/events/backfill.ts +0 -183
- package/src/events/documentId.ts +0 -56
- package/src/events/events.ts +0 -40
- package/src/events/identification.ts +0 -310
- package/src/events/index.ts +0 -14
- package/src/events/processors/AnalyticsProcessor.ts +0 -64
- package/src/events/processors/AuditLogsProcessor.ts +0 -93
- package/src/events/processors/LoggingProcessor.ts +0 -37
- package/src/events/processors/Processors.ts +0 -52
- package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -43
- package/src/events/processors/index.ts +0 -19
- package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
- package/src/events/processors/posthog/index.ts +0 -2
- package/src/events/processors/posthog/rateLimiting.ts +0 -106
- package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -168
- package/src/events/processors/types.ts +0 -1
- package/src/events/publishers/account.ts +0 -35
- package/src/events/publishers/app.ts +0 -155
- package/src/events/publishers/auditLog.ts +0 -26
- package/src/events/publishers/auth.ts +0 -73
- package/src/events/publishers/automation.ts +0 -110
- package/src/events/publishers/backfill.ts +0 -74
- package/src/events/publishers/backup.ts +0 -42
- package/src/events/publishers/datasource.ts +0 -48
- package/src/events/publishers/email.ts +0 -17
- package/src/events/publishers/environmentVariable.ts +0 -38
- package/src/events/publishers/group.ts +0 -99
- package/src/events/publishers/index.ts +0 -24
- package/src/events/publishers/installation.ts +0 -38
- package/src/events/publishers/layout.ts +0 -26
- package/src/events/publishers/license.ts +0 -84
- package/src/events/publishers/org.ts +0 -37
- package/src/events/publishers/plugin.ts +0 -47
- package/src/events/publishers/query.ts +0 -88
- package/src/events/publishers/role.ts +0 -62
- package/src/events/publishers/rows.ts +0 -29
- package/src/events/publishers/screen.ts +0 -36
- package/src/events/publishers/serve.ts +0 -43
- package/src/events/publishers/table.ts +0 -70
- package/src/events/publishers/user.ts +0 -202
- package/src/events/publishers/view.ts +0 -107
- package/src/featureFlags/index.ts +0 -77
- package/src/featureFlags/tests/featureFlags.spec.ts +0 -85
- package/src/helpers.ts +0 -9
- package/src/index.ts +0 -53
- package/src/installation.ts +0 -107
- package/src/logging/alerts.ts +0 -26
- package/src/logging/correlation/correlation.ts +0 -13
- package/src/logging/correlation/index.ts +0 -1
- package/src/logging/correlation/middleware.ts +0 -17
- package/src/logging/index.ts +0 -4
- package/src/logging/pino/logger.ts +0 -232
- package/src/logging/pino/middleware.ts +0 -45
- package/src/logging/system.ts +0 -81
- package/src/logging/tests/system.spec.ts +0 -61
- package/src/middleware/adminOnly.ts +0 -9
- package/src/middleware/auditLog.ts +0 -6
- package/src/middleware/authenticated.ts +0 -193
- package/src/middleware/builderOnly.ts +0 -20
- package/src/middleware/builderOrAdmin.ts +0 -20
- package/src/middleware/csrf.ts +0 -81
- package/src/middleware/errorHandling.ts +0 -29
- package/src/middleware/index.ts +0 -21
- package/src/middleware/internalApi.ts +0 -23
- package/src/middleware/joi-validator.ts +0 -45
- package/src/middleware/matchers.ts +0 -47
- package/src/middleware/passport/datasource/google.ts +0 -95
- package/src/middleware/passport/local.ts +0 -54
- package/src/middleware/passport/sso/google.ts +0 -77
- package/src/middleware/passport/sso/oidc.ts +0 -154
- package/src/middleware/passport/sso/sso.ts +0 -165
- package/src/middleware/passport/sso/tests/google.spec.ts +0 -67
- package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -152
- package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
- package/src/middleware/passport/utils.ts +0 -38
- package/src/middleware/querystringToBody.ts +0 -28
- package/src/middleware/tenancy.ts +0 -36
- package/src/middleware/tests/builder.spec.ts +0 -180
- package/src/middleware/tests/matchers.spec.ts +0 -134
- package/src/migrations/definitions.ts +0 -40
- package/src/migrations/index.ts +0 -2
- package/src/migrations/migrations.ts +0 -191
- package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
- package/src/migrations/tests/migrations.spec.ts +0 -64
- package/src/objectStore/buckets/app.ts +0 -40
- package/src/objectStore/buckets/global.ts +0 -29
- package/src/objectStore/buckets/index.ts +0 -3
- package/src/objectStore/buckets/plugins.ts +0 -71
- package/src/objectStore/buckets/tests/app.spec.ts +0 -171
- package/src/objectStore/buckets/tests/global.spec.ts +0 -74
- package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
- package/src/objectStore/cloudfront.ts +0 -41
- package/src/objectStore/index.ts +0 -3
- package/src/objectStore/objectStore.ts +0 -440
- package/src/objectStore/utils.ts +0 -27
- package/src/platform/index.ts +0 -3
- package/src/platform/platformDb.ts +0 -6
- package/src/platform/tenants.ts +0 -101
- package/src/platform/tests/tenants.spec.ts +0 -26
- package/src/platform/users.ts +0 -90
- package/src/plugin/index.ts +0 -1
- package/src/plugin/tests/validation.spec.ts +0 -83
- package/src/plugin/utils.ts +0 -156
- package/src/queue/constants.ts +0 -6
- package/src/queue/inMemoryQueue.ts +0 -141
- package/src/queue/index.ts +0 -2
- package/src/queue/listeners.ts +0 -195
- package/src/queue/queue.ts +0 -54
- package/src/redis/index.ts +0 -6
- package/src/redis/init.ts +0 -86
- package/src/redis/redis.ts +0 -308
- package/src/redis/redlockImpl.ts +0 -139
- package/src/redis/utils.ts +0 -117
- package/src/security/encryption.ts +0 -179
- package/src/security/permissions.ts +0 -159
- package/src/security/roles.ts +0 -420
- package/src/security/sessions.ts +0 -120
- package/src/security/tests/encryption.spec.ts +0 -31
- package/src/security/tests/permissions.spec.ts +0 -145
- package/src/security/tests/sessions.spec.ts +0 -12
- package/src/tenancy/db.ts +0 -6
- package/src/tenancy/index.ts +0 -2
- package/src/tenancy/tenancy.ts +0 -140
- package/src/tenancy/tests/tenancy.spec.ts +0 -184
- package/src/timers/index.ts +0 -1
- package/src/timers/timers.ts +0 -22
- package/src/users/db.ts +0 -460
- package/src/users/events.ts +0 -176
- package/src/users/index.ts +0 -4
- package/src/users/lookup.ts +0 -102
- package/src/users/users.ts +0 -276
- package/src/users/utils.ts +0 -55
- package/src/utils/hashing.ts +0 -14
- package/src/utils/index.ts +0 -3
- package/src/utils/stringUtils.ts +0 -8
- package/src/utils/tests/utils.spec.ts +0 -191
- package/src/utils/utils.ts +0 -239
- package/tests/core/logging.ts +0 -34
- package/tests/core/utilities/index.ts +0 -6
- package/tests/core/utilities/jestUtils.ts +0 -30
- package/tests/core/utilities/mocks/alerts.ts +0 -3
- package/tests/core/utilities/mocks/date.ts +0 -2
- package/tests/core/utilities/mocks/events.ts +0 -131
- package/tests/core/utilities/mocks/fetch.ts +0 -17
- package/tests/core/utilities/mocks/index.ts +0 -10
- package/tests/core/utilities/mocks/licenses.ts +0 -107
- package/tests/core/utilities/mocks/posthog.ts +0 -7
- package/tests/core/utilities/structures/Chance.ts +0 -20
- package/tests/core/utilities/structures/accounts.ts +0 -115
- package/tests/core/utilities/structures/apps.ts +0 -21
- package/tests/core/utilities/structures/common.ts +0 -7
- package/tests/core/utilities/structures/db.ts +0 -12
- package/tests/core/utilities/structures/documents/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
- package/tests/core/utilities/structures/generator.ts +0 -2
- package/tests/core/utilities/structures/index.ts +0 -15
- package/tests/core/utilities/structures/koa.ts +0 -16
- package/tests/core/utilities/structures/licenses.ts +0 -167
- package/tests/core/utilities/structures/plugins.ts +0 -19
- package/tests/core/utilities/structures/quotas.ts +0 -67
- package/tests/core/utilities/structures/scim.ts +0 -80
- package/tests/core/utilities/structures/shared.ts +0 -19
- package/tests/core/utilities/structures/sso.ts +0 -119
- package/tests/core/utilities/structures/tenants.ts +0 -5
- package/tests/core/utilities/structures/userGroups.ts +0 -10
- package/tests/core/utilities/structures/users.ts +0 -73
- package/tests/core/utilities/testContainerUtils.ts +0 -98
- package/tests/core/utilities/utils/index.ts +0 -1
- package/tests/core/utilities/utils/time.ts +0 -3
- package/tests/extra/DBTestConfiguration.ts +0 -36
- package/tests/extra/index.ts +0 -2
- package/tests/extra/testEnv.ts +0 -95
- package/tests/index.ts +0 -1
- package/tests/jestEnv.ts +0 -6
- package/tests/jestSetup.ts +0 -28
- package/tsconfig.build.json +0 -29
- 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
|
-
}
|
package/src/redis/redis.ts
DELETED
|
@@ -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
|
package/src/redis/redlockImpl.ts
DELETED
|
@@ -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
|
-
}
|
package/src/redis/utils.ts
DELETED
|
@@ -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
|
-
}
|