{"version":3,"sources":["../../src/cache/adapters/redis/index.ts"],"sourcesContent":["import { Cluster, Redis, type RedisOptions } from 'ioredis'\nimport { v } from 'valleyed'\n\nimport { EquippedError } from '../../../errors'\nimport { Instance } from '../../../instance'\nimport { configurable } from '../../../utilities'\nimport { Cache } from '../base'\n\nexport const redisConfigPipe = () =>\n\tv.meta(\n\t\tv.object({\n\t\t\thost: v.string(),\n\t\t\tport: v.optional(v.number()),\n\t\t\tpassword: v.optional(v.string()),\n\t\t\tusername: v.optional(v.string()),\n\t\t\ttls: v.optional(v.boolean()),\n\t\t\tcluster: v.optional(v.boolean()),\n\t\t}),\n\t\t{ title: 'Redis Config', $refId: 'RedisConfig' },\n\t)\n\nexport class RedisCache extends configurable(redisConfigPipe, Cache) {\n\t#client: Cluster | Redis\n\n\tprotected constructor(config: typeof RedisCache.Config, extraConfig?: Partial<RedisOptions>) {\n\t\tsuper(config)\n\t\tconst node = {\n\t\t\t...(config.host ? { host: config.host } : {}),\n\t\t\t...(config.port ? { port: config.port } : {}),\n\t\t}\n\t\tconst common = {\n\t\t\t...extraConfig,\n\t\t\t...(config.password ? { password: config.password } : {}),\n\t\t\t...(config.username ? { username: config.username } : {}),\n\t\t\t...(config.tls ? { tls: {} } : {}),\n\t\t\tlazyConnect: true,\n\t\t}\n\t\tthis.#client = config.cluster\n\t\t\t? new Cluster([node], {\n\t\t\t\t\t...extraConfig,\n\t\t\t\t\tredisOptions: common,\n\t\t\t\t\tlazyConnect: true,\n\t\t\t\t})\n\t\t\t: new Redis({ ...common, ...node })\n\t\tthis.#client.on('error', async (error) => {\n\t\t\tInstance.crash(new EquippedError(`Redis failed with error`, {}, error))\n\t\t})\n\t\tif (!extraConfig) Instance.on('start', async () => this.#client.connect(), { class: RedisCache })\n\t\tInstance.on('close', async () => this.#client.quit(), { class: RedisCache })\n\t}\n\n\tget connectionOptions() {\n\t\treturn this.#client.options\n\t}\n\n\tasync delete(key: string) {\n\t\tawait this.#client.del(this.getScopedKey(key))\n\t}\n\tasync get(key: string) {\n\t\treturn await this.#client.get(this.getScopedKey(key))\n\t}\n\tasync set(key: string, data: string, ttlInSecs?: number) {\n\t\tif (ttlInSecs) await this.#client.setex(this.getScopedKey(key), ttlInSecs, data)\n\t\telse this.#client.set(this.getScopedKey(key), data)\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, expectTypeOf, vi, beforeEach, afterEach } = import.meta.vitest\n\ttype PipeOutput<T> = import('valleyed').PipeOutput<T>\n\n\tlet hookCalls: Array<{ event: string; options?: any }>\n\n\tbeforeEach(() => {\n\t\thookCalls = []\n\t\tvi.spyOn(Instance, 'on').mockImplementation((event, _cb, options) => {\n\t\t\thookCalls.push({ event, options })\n\t\t})\n\t\tvi.spyOn(Instance, 'get').mockReturnValue({ getScopedName: (_name: string, _sep: string) => `test:${_name}` } as any)\n\t})\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks()\n\t})\n\n\tdescribe('RedisCache', () => {\n\t\ttest('create() produces a working instance', () => {\n\t\t\tconst cache = RedisCache.create({ host: 'localhost' })\n\t\t\texpect(cache).toBeInstanceOf(RedisCache)\n\t\t})\n\n\t\ttest('new RedisCache() is a compile error', () => {\n\t\t\t// @ts-expect-error — external `new` on a class with protected constructor is a compile error\n\t\t\tvoid (() => new RedisCache({ host: 'localhost' }))\n\t\t})\n\n\t\ttest('Instance.on calls use { class: RedisCache }', () => {\n\t\t\tRedisCache.create({ host: 'localhost' })\n\t\t\tconst startHook = hookCalls.find((h) => h.event === 'start')\n\t\t\tconst closeHook = hookCalls.find((h) => h.event === 'close')\n\t\t\texpect(startHook?.options).toEqual({ class: RedisCache })\n\t\t\texpect(closeHook?.options).toEqual({ class: RedisCache })\n\t\t})\n\n\t\ttest('skips start hook when extraConfig is provided', () => {\n\t\t\tRedisCache.create({ host: 'localhost' }, { maxRetriesPerRequest: null })\n\t\t\tconst startHooks = hookCalls.filter((h) => h.event === 'start')\n\t\t\tconst closeHooks = hookCalls.filter((h) => h.event === 'close')\n\t\t\texpect(startHooks).toHaveLength(0)\n\t\t\texpect(closeHooks).toHaveLength(1)\n\t\t})\n\n\t\ttest('Config type matches pipe output', () => {\n\t\t\ttype Expected = PipeOutput<ReturnType<typeof redisConfigPipe>>\n\t\t\texpectTypeOf<typeof RedisCache.Config>().toEqualTypeOf<Expected>()\n\t\t})\n\n\t\ttest('connectionOptions is accessible', () => {\n\t\t\tconst cache = RedisCache.create({ host: 'localhost', port: 6379 })\n\t\t\texpect(cache.connectionOptions).toBeDefined()\n\t\t})\n\t})\n}\n"],"mappings":"8IAAA,OAAS,WAAAA,EAAS,SAAAC,MAAgC,UAClD,OAAS,KAAAC,MAAS,WAOX,IAAMC,EAAkB,IAC9BC,EAAE,KACDA,EAAE,OAAO,CACR,KAAMA,EAAE,OAAO,EACf,KAAMA,EAAE,SAASA,EAAE,OAAO,CAAC,EAC3B,SAAUA,EAAE,SAASA,EAAE,OAAO,CAAC,EAC/B,SAAUA,EAAE,SAASA,EAAE,OAAO,CAAC,EAC/B,IAAKA,EAAE,SAASA,EAAE,QAAQ,CAAC,EAC3B,QAASA,EAAE,SAASA,EAAE,QAAQ,CAAC,CAChC,CAAC,EACD,CAAE,MAAO,eAAgB,OAAQ,aAAc,CAChD,EAEYC,EAAN,MAAMC,UAAmBC,EAAaJ,EAAiBK,CAAK,CAAE,CACpEC,GAEU,YAAYC,EAAkCC,EAAqC,CAC5F,MAAMD,CAAM,EACZ,IAAME,EAAO,CACZ,GAAIF,EAAO,KAAO,CAAE,KAAMA,EAAO,IAAK,EAAI,CAAC,EAC3C,GAAIA,EAAO,KAAO,CAAE,KAAMA,EAAO,IAAK,EAAI,CAAC,CAC5C,EACMG,EAAS,CACd,GAAGF,EACH,GAAID,EAAO,SAAW,CAAE,SAAUA,EAAO,QAAS,EAAI,CAAC,EACvD,GAAIA,EAAO,SAAW,CAAE,SAAUA,EAAO,QAAS,EAAI,CAAC,EACvD,GAAIA,EAAO,IAAM,CAAE,IAAK,CAAC,CAAE,EAAI,CAAC,EAChC,YAAa,EACd,EACA,KAAKD,GAAUC,EAAO,QACnB,IAAII,EAAQ,CAACF,CAAI,EAAG,CACpB,GAAGD,EACH,aAAcE,EACd,YAAa,EACd,CAAC,EACA,IAAIE,EAAM,CAAE,GAAGF,EAAQ,GAAGD,CAAK,CAAC,EACnC,KAAKH,GAAQ,GAAG,QAAS,MAAOO,GAAU,CACzCC,EAAS,MAAM,IAAIC,EAAc,0BAA2B,CAAC,EAAGF,CAAK,CAAC,CACvE,CAAC,EACIL,GAAaM,EAAS,GAAG,QAAS,SAAY,KAAKR,GAAQ,QAAQ,EAAG,CAAE,MAAOH,CAAW,CAAC,EAChGW,EAAS,GAAG,QAAS,SAAY,KAAKR,GAAQ,KAAK,EAAG,CAAE,MAAOH,CAAW,CAAC,CAC5E,CAEA,IAAI,mBAAoB,CACvB,OAAO,KAAKG,GAAQ,OACrB,CAEA,MAAM,OAAOU,EAAa,CACzB,MAAM,KAAKV,GAAQ,IAAI,KAAK,aAAaU,CAAG,CAAC,CAC9C,CACA,MAAM,IAAIA,EAAa,CACtB,OAAO,MAAM,KAAKV,GAAQ,IAAI,KAAK,aAAaU,CAAG,CAAC,CACrD,CACA,MAAM,IAAIA,EAAaC,EAAcC,EAAoB,CACpDA,EAAW,MAAM,KAAKZ,GAAQ,MAAM,KAAK,aAAaU,CAAG,EAAGE,EAAWD,CAAI,EAC1E,KAAKX,GAAQ,IAAI,KAAK,aAAaU,CAAG,EAAGC,CAAI,CACnD,CACD","names":["Cluster","Redis","v","redisConfigPipe","v","RedisCache","_RedisCache","configurable","Cache","#client","config","extraConfig","node","common","Cluster","Redis","error","Instance","EquippedError","key","data","ttlInSecs"]}