diff --git a/lerna.json b/lerna.json index d0e9af5766..5c2ae9ec8b 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.6.19-alpha.39", + "version": "2.6.19-alpha.42", "npmClient": "yarn", "packages": [ "packages/backend-core", diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index f04437c066..f85687b007 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -33,7 +33,7 @@ "correlation-id": "4.0.0", "dotenv": "16.0.1", "emitter-listener": "1.1.2", - "ioredis": "4.28.0", + "ioredis": "5.3.2", "joi": "17.6.0", "jsonwebtoken": "9.0.0", "koa-passport": "4.1.4", @@ -62,7 +62,6 @@ "@swc/jest": "^0.2.24", "@trendyol/jest-testcontainers": "^2.1.1", "@types/chance": "1.1.3", - "@types/ioredis": "4.28.0", "@types/jest": "29.5.0", "@types/koa": "2.13.4", "@types/lodash": "4.14.180", @@ -74,7 +73,7 @@ "@types/tar-fs": "2.0.1", "@types/uuid": "8.3.4", "chance": "1.1.8", - "ioredis-mock": "5.8.0", + "ioredis-mock": "8.7.0", "jest": "29.5.0", "jest-environment-node": "29.5.0", "jest-serial-runner": "^1.2.1", diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 9163dfeba6..eab8cd4c45 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -97,7 +97,6 @@ const environment = { REDIS_URL: process.env.REDIS_URL || "localhost:6379", REDIS_PASSWORD: process.env.REDIS_PASSWORD, REDIS_CLUSTERED: process.env.REDIS_CLUSTERED, - MOCK_REDIS: process.env.MOCK_REDIS, MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, AWS_REGION: process.env.AWS_REGION, @@ -129,6 +128,7 @@ const environment = { PLUGIN_BUCKET_NAME: process.env.PLUGIN_BUCKET_NAME || DefaultBucketName.PLUGINS, USE_COUCH: process.env.USE_COUCH || true, + MOCK_REDIS: process.env.MOCK_REDIS, DEFAULT_LICENSE: process.env.DEFAULT_LICENSE, SERVICE: process.env.SERVICE || "budibase", LOG_LEVEL: process.env.LOG_LEVEL || "info", diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index 40233b3827..7b98674788 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -21,6 +21,7 @@ export * as context from "./context" export * as cache from "./cache" export * as objectStore from "./objectStore" export * as redis from "./redis" +export { Client as RedisClient } from "./redis" export * as locks from "./redis/redlockImpl" export * as utils from "./utils" export * as errors from "./errors" diff --git a/packages/backend-core/src/redis/redis.ts b/packages/backend-core/src/redis/redis.ts index f25de9be2b..636544897d 100644 --- a/packages/backend-core/src/redis/redis.ts +++ b/packages/backend-core/src/redis/redis.ts @@ -1,6 +1,7 @@ import env from "../environment" +import Redis from "ioredis" // ioredis mock is all in memory -const Redis = env.MOCK_REDIS ? require("ioredis-mock") : require("ioredis") +const MockRedis = require("ioredis-mock") import { addDbPrefix, removeDbPrefix, @@ -18,7 +19,7 @@ const DEFAULT_SELECT_DB = SelectableDatabase.DEFAULT // for testing just generate the client once let CLOSED = false let CLIENTS: { [key: number]: any } = {} - +0 let CONNECTED = false // mock redis always connected @@ -55,6 +56,7 @@ function connectionError( * will return the ioredis client which will be ready to use. */ function init(selectDb = DEFAULT_SELECT_DB) { + const RedisCore = env.MOCK_REDIS ? MockRedis : Redis let timeout: NodeJS.Timeout CLOSED = false let client = pickClient(selectDb) @@ -64,7 +66,7 @@ function init(selectDb = DEFAULT_SELECT_DB) { } // testing uses a single in memory client if (env.MOCK_REDIS) { - CLIENTS[selectDb] = new Redis(getRedisOptions()) + CLIENTS[selectDb] = new RedisCore(getRedisOptions()) } // start the timer - only allowed 5 seconds to connect timeout = setTimeout(() => { @@ -84,11 +86,11 @@ function init(selectDb = DEFAULT_SELECT_DB) { const { redisProtocolUrl, opts, host, port } = getRedisOptions() if (CLUSTERED) { - client = new Redis.Cluster([{ host, port }], opts) + client = new RedisCore.Cluster([{ host, port }], opts) } else if (redisProtocolUrl) { - client = new Redis(redisProtocolUrl) + client = new RedisCore(redisProtocolUrl) } else { - client = new Redis(opts) + client = new RedisCore(opts) } // attach handlers client.on("end", (err: Error) => { diff --git a/packages/backend-core/src/redis/utils.ts b/packages/backend-core/src/redis/utils.ts index b57dd58d57..34b7275a2b 100644 --- a/packages/backend-core/src/redis/utils.ts +++ b/packages/backend-core/src/redis/utils.ts @@ -95,7 +95,7 @@ export function getRedisOptions() { opts.port = port opts.password = password } - return { opts, host, port, redisProtocolUrl } + return { opts, host, port: parseInt(port), redisProtocolUrl } } export function addDbPrefix(db: string, key: string) { diff --git a/packages/pro b/packages/pro index 86c32b80e0..cd06642b86 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 86c32b80e08d2f19b57dcc2a3159667ac5a86c21 +Subproject commit cd06642b860111aa1bd3443ee10076ca3abf03c3 diff --git a/packages/server/package.json b/packages/server/package.json index cb53a1618e..c73bba0f16 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -80,6 +80,7 @@ "global-agent": "3.0.0", "google-auth-library": "7.12.0", "google-spreadsheet": "3.2.0", + "ioredis": "5.3.2", "jimp": "0.16.1", "joi": "17.6.0", "js-yaml": "4.1.0", @@ -122,8 +123,8 @@ "validate.js": "0.13.1", "vm2": "3.9.17", "worker-farm": "1.7.0", - "yargs": "13.2.4", - "xml2js": "0.5.0" + "xml2js": "0.5.0", + "yargs": "13.2.4" }, "devDependencies": { "@babel/core": "7.17.4", @@ -137,7 +138,6 @@ "@types/bson": "4.2.0", "@types/global-agent": "2.1.1", "@types/google-spreadsheet": "3.1.5", - "@types/ioredis": "4.28.10", "@types/jest": "29.5.0", "@types/koa": "2.13.4", "@types/koa__router": "8.0.8", @@ -157,7 +157,6 @@ "copyfiles": "2.4.1", "docker-compose": "0.23.17", "eslint": "6.8.0", - "ioredis-mock": "7.2.0", "is-wsl": "2.2.0", "jest": "29.5.0", "jest-openapi": "0.14.2", diff --git a/packages/server/src/api/controllers/datasource.ts b/packages/server/src/api/controllers/datasource.ts index 9852b01bc5..8fe0ab70da 100644 --- a/packages/server/src/api/controllers/datasource.ts +++ b/packages/server/src/api/controllers/datasource.ts @@ -21,6 +21,7 @@ import { CreateDatasourceRequest, VerifyDatasourceRequest, VerifyDatasourceResponse, + FetchDatasourceInfoRequest, FetchDatasourceInfoResponse, IntegrationBase, DatasourcePlus, @@ -57,6 +58,21 @@ async function getConnector( return new Connector(datasource.config) } +async function getAndMergeDatasource(datasource: Datasource) { + let existingDatasource: undefined | Datasource + if (datasource._id) { + existingDatasource = await sdk.datasources.get(datasource._id) + } + let enrichedDatasource = datasource + if (existingDatasource) { + enrichedDatasource = sdk.datasources.mergeConfigs( + datasource, + existingDatasource + ) + } + return await sdk.datasources.enrich(enrichedDatasource) +} + async function buildSchemaHelper(datasource: Datasource) { const connector = (await getConnector(datasource)) as DatasourcePlus await connector.buildSchema(datasource._id!, datasource.entities!) @@ -132,17 +148,7 @@ export async function verify( ctx: UserCtx ) { const { datasource } = ctx.request.body - let existingDatasource: undefined | Datasource - if (datasource._id) { - existingDatasource = await sdk.datasources.get(datasource._id) - } - let enrichedDatasource = datasource - if (existingDatasource) { - enrichedDatasource = sdk.datasources.mergeConfigs( - datasource, - existingDatasource - ) - } + const enrichedDatasource = await getAndMergeDatasource(datasource) const connector = await getConnector(enrichedDatasource) if (!connector.testConnection) { ctx.throw(400, "Connection information verification not supported") @@ -156,11 +162,11 @@ export async function verify( } export async function information( - ctx: UserCtx + ctx: UserCtx ) { - const datasourceId = ctx.params.datasourceId - const datasource = await sdk.datasources.get(datasourceId, { enriched: true }) - const connector = (await getConnector(datasource)) as DatasourcePlus + const { datasource } = ctx.request.body + const enrichedDatasource = await getAndMergeDatasource(datasource) + const connector = (await getConnector(enrichedDatasource)) as DatasourcePlus if (!connector.getTableNames) { ctx.throw(400, "Table name fetching not supported by datasource") } @@ -297,7 +303,7 @@ export async function update(ctx: UserCtx) { ctx.body = { datasource: await sdk.datasources.removeSecretSingle(datasource), } - builderSocket.emitDatasourceUpdate(ctx, datasource) + builderSocket?.emitDatasourceUpdate(ctx, datasource) } export async function save( @@ -340,7 +346,7 @@ export async function save( response.error = schemaError } ctx.body = response - builderSocket.emitDatasourceUpdate(ctx, datasource) + builderSocket?.emitDatasourceUpdate(ctx, datasource) } async function destroyInternalTablesBySourceId(datasourceId: string) { @@ -400,7 +406,7 @@ export async function destroy(ctx: UserCtx) { ctx.message = `Datasource deleted.` ctx.status = 200 - builderSocket.emitDatasourceDeletion(ctx, datasourceId) + builderSocket?.emitDatasourceDeletion(ctx, datasourceId) } export async function find(ctx: UserCtx) { diff --git a/packages/server/src/api/controllers/plugin/index.ts b/packages/server/src/api/controllers/plugin/index.ts index 31a3468178..a8a451c98c 100644 --- a/packages/server/src/api/controllers/plugin/index.ts +++ b/packages/server/src/api/controllers/plugin/index.ts @@ -71,7 +71,7 @@ export async function create(ctx: any) { const doc = await pro.plugins.storePlugin(metadata, directory, source) - clientAppSocket.emit("plugins-update", { name, hash: doc.hash }) + clientAppSocket?.emit("plugins-update", { name, hash: doc.hash }) ctx.body = { message: "Plugin uploaded successfully", plugins: [doc], diff --git a/packages/server/src/api/controllers/table/index.ts b/packages/server/src/api/controllers/table/index.ts index 271f3e82fa..5ade77592a 100644 --- a/packages/server/src/api/controllers/table/index.ts +++ b/packages/server/src/api/controllers/table/index.ts @@ -78,7 +78,7 @@ export async function save(ctx: UserCtx) { ctx.eventEmitter && ctx.eventEmitter.emitTable(`table:save`, appId, savedTable) ctx.body = savedTable - builderSocket.emitTableUpdate(ctx, savedTable) + builderSocket?.emitTableUpdate(ctx, savedTable) } export async function destroy(ctx: UserCtx) { @@ -91,7 +91,7 @@ export async function destroy(ctx: UserCtx) { ctx.status = 200 ctx.table = deletedTable ctx.body = { message: `Table ${tableId} deleted.` } - builderSocket.emitTableDeletion(ctx, tableId) + builderSocket?.emitTableDeletion(ctx, tableId) } export async function bulkImport(ctx: UserCtx) { diff --git a/packages/server/src/api/controllers/view/index.ts b/packages/server/src/api/controllers/view/index.ts index 28b0d0a81f..b194f3cb5e 100644 --- a/packages/server/src/api/controllers/view/index.ts +++ b/packages/server/src/api/controllers/view/index.ts @@ -58,7 +58,7 @@ export async function save(ctx: Ctx) { await handleViewEvents(existingTable.views[viewName], table.views[viewName]) ctx.body = table.views[viewName] - builderSocket.emitTableUpdate(ctx, table) + builderSocket?.emitTableUpdate(ctx, table) } export async function calculationEvents(existingView: View, newView: View) { @@ -127,7 +127,7 @@ export async function destroy(ctx: Ctx) { await events.view.deleted(view) ctx.body = view - builderSocket.emitTableUpdate(ctx, table) + builderSocket?.emitTableUpdate(ctx, table) } export async function exportView(ctx: Ctx) { diff --git a/packages/server/src/api/routes/datasource.ts b/packages/server/src/api/routes/datasource.ts index ac8256539c..f874d3c4aa 100644 --- a/packages/server/src/api/routes/datasource.ts +++ b/packages/server/src/api/routes/datasource.ts @@ -20,8 +20,8 @@ router authorized(permissions.BUILDER), datasourceController.verify ) - .get( - "/api/datasources/:datasourceId/info", + .post( + "/api/datasources/info", authorized(permissions.BUILDER), datasourceController.information ) diff --git a/packages/server/src/api/routes/tests/view.spec.js b/packages/server/src/api/routes/tests/view.spec.js index 522987ab29..df07ffa4af 100644 --- a/packages/server/src/api/routes/tests/view.spec.js +++ b/packages/server/src/api/routes/tests/view.spec.js @@ -114,8 +114,8 @@ describe("/views", () => { expect(res.body.tableId).toBe(table._id) const updatedTable = await config.getTable(table._id) - expect(updatedTable.views).toEqual({ - TestView: { + const expectedObj = expect.objectContaining({ + TestView: expect.objectContaining({ field: "Price", calculation: "stats", tableId: table._id, @@ -143,8 +143,9 @@ describe("/views", () => { type: "string", }, }, - }, + }), }) + expect(updatedTable.views).toEqual(expectedObj) }) }) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index ce16ca4aba..f72cbda1ea 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -25,6 +25,7 @@ const config = setup.getConfig()! jest.setTimeout(30000) jest.unmock("pg") +jest.mock("../websockets") describe("postgres integrations", () => { let makeRequest: MakeRequestResponse, @@ -1055,13 +1056,12 @@ describe("postgres integrations", () => { }) }) - describe("GET /api/datasources/:datasourceId/info", () => { + describe("POST /api/datasources/info", () => { it("should fetch information about postgres datasource", async () => { const primaryName = primaryPostgresTable.name - const response = await makeRequest( - "get", - `/api/datasources/${postgresDatasource._id}/info` - ) + const response = await makeRequest("post", "/api/datasources/info", { + datasource: postgresDatasource, + }) expect(response.status).toBe(200) expect(response.body.tableNames).toBeDefined() expect(response.body.tableNames.indexOf(primaryName)).not.toBe(-1) diff --git a/packages/server/src/integrations/redis.ts b/packages/server/src/integrations/redis.ts index 26666ac800..a6372c8e13 100644 --- a/packages/server/src/integrations/redis.ts +++ b/packages/server/src/integrations/redis.ts @@ -177,7 +177,13 @@ class RedisIntegration { const pipeline = this.client.pipeline(pipelineCommands) const result = await pipeline.exec() - return result.map((output: string | string[]) => output[1]) + return result?.map((output: any) => { + if (typeof output === "string") { + return output + } else if (Array.isArray(output)) { + return output[1] + } + }) }) } } diff --git a/packages/server/src/sdk/plugins/plugins.ts b/packages/server/src/sdk/plugins/plugins.ts index 02000410bf..f6c26ca339 100644 --- a/packages/server/src/sdk/plugins/plugins.ts +++ b/packages/server/src/sdk/plugins/plugins.ts @@ -36,6 +36,6 @@ export async function processUploaded(plugin: FileType, source?: PluginSource) { } const doc = await pro.plugins.storePlugin(metadata, directory, source) - clientAppSocket.emit("plugin-update", { name: doc.name, hash: doc.hash }) + clientAppSocket?.emit("plugin-update", { name: doc.name, hash: doc.hash }) return doc } diff --git a/packages/server/src/threads/automation.ts b/packages/server/src/threads/automation.ts index 6ed8506b85..9831a96936 100644 --- a/packages/server/src/threads/automation.ts +++ b/packages/server/src/threads/automation.ts @@ -44,10 +44,18 @@ function getLoopIterations(loopStep: LoopStep) { if (!binding) { return 0 } + const isString = typeof binding === "string" + try { + if (isString) { + binding = JSON.parse(binding) + } + } catch (err) { + // ignore error - wasn't able to parse + } if (Array.isArray(binding)) { return binding.length } - if (typeof binding === "string") { + if (isString) { return automationUtils.stringSplit(binding).length } return 0 diff --git a/packages/server/src/utilities/redis.ts b/packages/server/src/utilities/redis.ts index 5785d79d2a..d833ed2c10 100644 --- a/packages/server/src/utilities/redis.ts +++ b/packages/server/src/utilities/redis.ts @@ -1,13 +1,16 @@ -import { redis } from "@budibase/backend-core" +import { redis, RedisClient } from "@budibase/backend-core" import { getGlobalIDFromUserMetadataID } from "../db/utils" import { ContextUser } from "@budibase/types" +import env from "../environment" const APP_DEV_LOCK_SECONDS = 600 const AUTOMATION_TEST_FLAG_SECONDS = 60 -let devAppClient: any, debounceClient: any, flagClient: any +let devAppClient: RedisClient, + debounceClient: RedisClient, + flagClient: RedisClient // We need to maintain a duplicate client for socket.io pub/sub -let socketClient: any +let socketClient: RedisClient let socketSubClient: any // We init this as we want to keep the connection open all the time @@ -22,7 +25,9 @@ export async function init() { // Duplicate the socket client for pub/sub socketClient = await redis.clients.getSocketClient() - socketSubClient = socketClient.getClient().duplicate() + if (!env.isTest()) { + socketSubClient = socketClient.getClient().duplicate() + } } export async function shutdown() { diff --git a/packages/server/src/websockets/builder.ts b/packages/server/src/websockets/builder.ts index 5e0e094b9e..ff7c50ebf4 100644 --- a/packages/server/src/websockets/builder.ts +++ b/packages/server/src/websockets/builder.ts @@ -14,9 +14,9 @@ export default class BuilderSocket extends BaseSocket { super(app, server, "/socket/builder", [authorized(permissions.BUILDER)]) } - async onConnect(socket: Socket) { + async onConnect(socket?: Socket) { // Initial identification of selected app - socket.on(BuilderSocketEvent.SelectApp, async (appId, callback) => { + socket?.on(BuilderSocketEvent.SelectApp, async (appId, callback) => { await this.joinRoom(socket, appId) // Reply with all users in current room @@ -49,14 +49,14 @@ export default class BuilderSocket extends BaseSocket { this.io .in(ctx.appId) .emit(BuilderSocketEvent.TableChange, { id: table._id, table }) - gridSocket.emitTableUpdate(table) + gridSocket?.emitTableUpdate(table) } emitTableDeletion(ctx: any, id: string) { this.io .in(ctx.appId) .emit(BuilderSocketEvent.TableChange, { id, table: null }) - gridSocket.emitTableDeletion(id) + gridSocket?.emitTableDeletion(id) } emitDatasourceUpdate(ctx: any, datasource: Datasource) { diff --git a/packages/server/src/websockets/index.ts b/packages/server/src/websockets/index.ts index b74a8adfca..bb530b559e 100644 --- a/packages/server/src/websockets/index.ts +++ b/packages/server/src/websockets/index.ts @@ -3,15 +3,19 @@ import Koa from "koa" import ClientAppSocket from "./client" import GridSocket from "./grid" import BuilderSocket from "./builder" +import env from "../environment" -let clientAppSocket: ClientAppSocket -let gridSocket: GridSocket -let builderSocket: BuilderSocket +let clientAppSocket: ClientAppSocket | undefined +let gridSocket: GridSocket | undefined +let builderSocket: BuilderSocket | undefined export const initialise = (app: Koa, server: http.Server) => { - clientAppSocket = new ClientAppSocket(app, server) - gridSocket = new GridSocket(app, server) - builderSocket = new BuilderSocket(app, server) + // have to remove these for testing until ioredis-mock can be fully removed + if (!env.isTest()) { + clientAppSocket = new ClientAppSocket(app, server) + gridSocket = new GridSocket(app, server) + builderSocket = new BuilderSocket(app, server) + } } export { clientAppSocket, gridSocket, builderSocket } diff --git a/packages/types/src/api/web/app/datasource.ts b/packages/types/src/api/web/app/datasource.ts index d15f65eb35..d692f17421 100644 --- a/packages/types/src/api/web/app/datasource.ts +++ b/packages/types/src/api/web/app/datasource.ts @@ -23,6 +23,10 @@ export interface VerifyDatasourceResponse { error?: string } +export interface FetchDatasourceInfoRequest { + datasource: Datasource +} + export interface FetchDatasourceInfoResponse { tableNames: string[] } diff --git a/yarn.lock b/yarn.lock index 2f58e5fa66..9a57eb4377 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2591,6 +2591,16 @@ resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== +"@ioredis/as-callback@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@ioredis/as-callback/-/as-callback-3.0.0.tgz#b96c9b05e6701e85ec6a5e62fa254071b0aec97f" + integrity sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg== + +"@ioredis/commands@^1.1.1", "@ioredis/commands@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== + "@isaacs/string-locale-compare@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" @@ -5649,13 +5659,6 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== -"@types/ioredis@4.28.0": - version "4.28.0" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.0.tgz#609b2ea0d91231df2dd7f67dd77436bc72584911" - integrity sha512-HSA/JQivJgV0e+353gvgu6WVoWvGRe0HyHOnAN2AvbVIhUlJBhNnnkP8gEEokrDWrxywrBkwo8NuDZ6TVPL9XA== - dependencies: - "@types/node" "*" - "@types/ioredis@4.28.10": version "4.28.10" resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.10.tgz#40ceb157a4141088d1394bb87c98ed09a75a06ff" @@ -11956,7 +11959,7 @@ fecha@^4.2.0: resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== -fengari-interop@^0.1.2, fengari-interop@^0.1.3: +fengari-interop@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/fengari-interop/-/fengari-interop-0.1.3.tgz#3ad37a90e7430b69b365441e9fc0ba168942a146" integrity sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw== @@ -13993,39 +13996,28 @@ invert-kv@^2.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== -ioredis-mock@5.8.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-5.8.0.tgz#99d3f0fe58419c2ff15c81cb4e13709aff8f2a44" - integrity sha512-PokVyNC/d3qaAyHAdf+Ex4HHBe7GdaSGrcn8pP7ran+pVmSrJ6Aofwm7Od5bQ5JtjDSiylEtIoZzEPYIjUKMHA== - dependencies: - fengari "^0.1.4" - fengari-interop "^0.1.2" - lodash "^4.17.21" - standard-as-callback "^2.1.0" - -ioredis-mock@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-7.2.0.tgz#48f006c07ef7f1f93f75e60d8f9035fa46c4ef0a" - integrity sha512-xzABBG3NhfDBGxH1KX9n6vs7WGNn9lhcxMT3b+vjynVImxlUV+vOXU+tjGzSUnGmx4IYllA8RqbXN8z6ROMPVA== +ioredis-mock@8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-8.7.0.tgz#9877a85e0d233e1b49123d1c6e320df01e9a1d36" + integrity sha512-BJcSjkR3sIMKbH93fpFzwlWi/jl1kd5I3vLvGQxnJ/W/6bD2ksrxnyQN186ljAp3Foz4p1ivViDE3rZeKEAluA== dependencies: + "@ioredis/as-callback" "^3.0.0" + "@ioredis/commands" "^1.2.0" fengari "^0.1.4" fengari-interop "^0.1.3" - redis-commands "^1.7.0" - standard-as-callback "^2.1.0" + semver "^7.3.8" -ioredis@4.28.0: - version "4.28.0" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.0.tgz#5a2be3f37ff2075e2332f280eaeb02ab4d9ff0d3" - integrity sha512-I+zkeeWp3XFgPT2CtJKxvaF5FjGBGt4yGYljRjQecdQKteThuAsKqffeF1lgHVlYnuNeozRbPOCDNZ7tDWPeig== +ioredis@5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.3.2.tgz#9139f596f62fc9c72d873353ac5395bcf05709f7" + integrity sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA== dependencies: + "@ioredis/commands" "^1.1.1" cluster-key-slot "^1.1.0" - debug "^4.3.1" - denque "^1.1.0" + debug "^4.3.4" + denque "^2.1.0" lodash.defaults "^4.2.0" - lodash.flatten "^4.4.0" lodash.isarguments "^3.1.0" - p-map "^2.1.0" - redis-commands "1.7.0" redis-errors "^1.2.0" redis-parser "^3.0.0" standard-as-callback "^2.1.0" @@ -21759,7 +21751,7 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -redis-commands@1.7.0, redis-commands@^1.7.0: +redis-commands@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==