diff --git a/package-lock.json b/package-lock.json index 40769f3a..2e7a7f4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,8 @@ "typescript": "^5.7.2" }, "optionalDependencies": { - "ioredis": "^5.3.2" + "ioredis": "^5.3.2", + "redis": "^5.8.2" }, "peerDependencies": { "graphql-subscriptions": "^1.0.0 || ^2.0.0 || ^3.0.0" @@ -680,6 +681,71 @@ "node": ">= 8" } }, + "node_modules/@redis/bloom": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-5.8.2.tgz", + "integrity": "sha512-855DR0ChetZLarblio5eM0yLwxA9Dqq50t8StXKp5bAtLT0G+rZ+eRzzqxl37sPqQKjUudSYypz55o6nNhbz0A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, + "node_modules/@redis/client": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.8.2.tgz", + "integrity": "sha512-WtMScno3+eBpTac1Uav2zugXEoXqaU23YznwvFgkPwBQVwEHTDgOG7uEAObtZ/Nyn8SmAMbqkEubJaMOvnqdsQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "cluster-key-slot": "1.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@redis/json": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-5.8.2.tgz", + "integrity": "sha512-uxpVfas3I0LccBX9rIfDgJ0dBrUa3+0Gc8sEwmQQH0vHi7C1Rx1Qn8Nv1QWz5bohoeIXMICFZRcyDONvum2l/w==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, + "node_modules/@redis/search": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-5.8.2.tgz", + "integrity": "sha512-cNv7HlgayavCBXqPXgaS97DRPVWFznuzsAmmuemi2TMCx5scwLiP50TeZvUS06h/MG96YNPe6A0Zt57yayfxwA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, + "node_modules/@redis/time-series": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-5.8.2.tgz", + "integrity": "sha512-g2NlHM07fK8H4k+613NBsk3y70R2JIM2dPMSkhIjl2Z17SYvaYKdusz85d7VYOrZBWtDrHV/WD2E3vGu+zni8A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@redis/client": "^5.8.2" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", @@ -1011,24 +1077,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", - "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.18.0", - "@typescript-eslint/visitor-keys": "8.18.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/type-utils": { "version": "8.24.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz", @@ -1164,73 +1212,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", - "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", - "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.18.0", - "@typescript-eslint/visitor-keys": "8.18.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { "version": "8.24.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.1.tgz", @@ -1384,37 +1365,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", - "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.18.0", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@ungap/structured-clone": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", @@ -1836,10 +1786,11 @@ } }, "node_modules/cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "devOptional": true, + "license": "Apache-2.0", "engines": { "node": ">=0.10.0" } @@ -3812,6 +3763,23 @@ "node": ">=8.10.0" } }, + "node_modules/redis": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-5.8.2.tgz", + "integrity": "sha512-31vunZj07++Y1vcFGcnNWEf5jPoTkGARgfWI4+Tk55vdwHxhAvug8VEtW7Cx+/h47NuJTEg/JL77zAwC6E0OeA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@redis/bloom": "5.8.2", + "@redis/client": "5.8.2", + "@redis/json": "5.8.2", + "@redis/search": "5.8.2", + "@redis/time-series": "5.8.2" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -4116,19 +4084,6 @@ "node": ">=8.0" } }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", diff --git a/package.json b/package.json index 9e65e1c2..5701169b 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,8 @@ "typescript": "^5.7.2" }, "optionalDependencies": { - "ioredis": "^5.3.2" + "ioredis": "^5.3.2", + "redis": "^5.8.2" }, "typings": "dist/index.d.ts", "typescript": { diff --git a/src/redis-pubsub.ts b/src/redis-pubsub.ts index 6e25e4fb..61dd1cc2 100644 --- a/src/redis-pubsub.ts +++ b/src/redis-pubsub.ts @@ -1,13 +1,25 @@ import {Cluster, Redis, RedisOptions} from 'ioredis'; +import { RedisClusterType, RedisClientType, RedisClientOptions, RedisClusterOptions } from 'redis'; import {PubSubEngine} from 'graphql-subscriptions'; import {PubSubAsyncIterator} from './pubsub-async-iterator'; -type RedisClient = Redis | Cluster; +type RedisClient = Redis | Cluster | RedisClientType | RedisClusterType; type OnMessage = (message: T) => void; type DeserializerContext = { channel: string, pattern?: string }; -export interface PubSubRedisOptions { - connection?: RedisOptions | string; +type OptionsType + = R extends Redis + ? RedisOptions | string + : R extends Cluster + ? RedisOptions | string + : R extends RedisClientType + ? RedisClientOptions + : R extends RedisClusterType + ? RedisClusterOptions + : never + +export interface PubSubRedisOptions { + connection?: OptionsType; triggerTransform?: TriggerTransform; connectionListener?: (err: Error) => void; publisher?: RedisClient; @@ -19,9 +31,9 @@ export interface PubSubRedisOptions { pmessageEventName?: string; } -export class RedisPubSub implements PubSubEngine { +export class RedisPubSub implements PubSubEngine { - constructor(options: PubSubRedisOptions = {}) { + constructor(options: PubSubRedisOptions = {}) { const { triggerTransform, connection, @@ -127,7 +139,8 @@ export class RedisPubSub implements PubSubEngine { subsPendingRefsMap.set(triggerName, { refs: [], pending }); const sub = new Promise((resolve, reject) => { - const subscribeFn = options['pattern'] ? this.redisSubscriber.psubscribe : this.redisSubscriber.subscribe; + const psubfn = 'psubscribe' in this.redisSubscriber ? this.redisSubscriber.psubscribe : this.redisSubscriber.pSubscribe + const subscribeFn = options['pattern'] ? psubfn : this.redisSubscriber.subscribe; subscribeFn.call(this.redisSubscriber, triggerName, err => { if (err) { @@ -159,7 +172,8 @@ export class RedisPubSub implements PubSubEngine { if (refs.size === 1) { // unsubscribe from specific channel and pattern match this.redisSubscriber.unsubscribe(triggerName); - this.redisSubscriber.punsubscribe(triggerName); + const punsubfn = 'punsubscribe' in this.redisSubscriber ? this.redisSubscriber.punsubscribe : this.redisSubscriber.pUnsubscribe + punsubfn.call(this.redisSubscriber, triggerName); this.subsRefsMap.delete(triggerName); } else { @@ -185,10 +199,12 @@ export class RedisPubSub implements PubSubEngine { } public close(): Promise<'OK'[]> { + const pubQuit = 'close' in this.redisPublisher ? this.redisPublisher.close : this.redisPublisher.quit + const subQuit = 'close' in this.redisSubscriber ? this.redisSubscriber.close : this.redisSubscriber.quit return Promise.all([ - this.redisPublisher.quit(), - this.redisSubscriber.quit(), - ]); + pubQuit.call(this.redisPublisher), + subQuit.call(this.redisSubscriber), + ]).then(OkOrVoids => OkOrVoids.map(ok => ok || 'OK' as const)); } private readonly serializer?: Serializer;