{"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":"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","names":[]}