deprecate @umami/redis-client, add redis lib
Some checks failed
Node.js CI / build (push) Has been cancelled

This commit is contained in:
Francis Cao 2026-02-18 09:23:27 -08:00
parent 99a328359b
commit 8530329e14
3 changed files with 109 additions and 19 deletions

View file

@ -67,7 +67,6 @@
"@svgr/cli": "^8.1.0",
"@tanstack/react-query": "^5.90.21",
"@umami/react-zen": "^0.245.0",
"@umami/redis-client": "^0.30.0",
"bcryptjs": "^3.0.2",
"chalk": "^5.6.2",
"chart.js": "^4.5.1",
@ -110,6 +109,7 @@
"react-simple-maps": "^2.3.0",
"react-use-measure": "^2.0.4",
"react-window": "^1.8.6",
"redis": "^4.5.1",
"request-ip": "^3.3.0",
"semver": "^7.7.4",
"serialize-error": "^12.0.0",

18
pnpm-lock.yaml generated
View file

@ -44,9 +44,6 @@ importers:
'@umami/react-zen':
specifier: ^0.245.0
version: 0.245.0(@types/react@19.2.14)(immer@10.2.0)(react-aria-components@1.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(use-sync-external-store@1.6.0(react@19.2.4))
'@umami/redis-client':
specifier: ^0.30.0
version: 0.30.0
bcryptjs:
specifier: ^3.0.2
version: 3.0.3
@ -173,6 +170,9 @@ importers:
react-window:
specifier: ^1.8.6
version: 1.8.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
redis:
specifier: ^4.5.1
version: 4.7.1
request-ip:
specifier: ^3.3.0
version: 3.3.0
@ -328,8 +328,6 @@ importers:
specifier: ^5.9.3
version: 5.9.3
dist: {}
packages:
'@ampproject/remapping@2.3.0':
@ -2965,9 +2963,6 @@ packages:
react-aria-components: ^1.0.0
react-dom: ^18.0.0 || ^19.0.0
'@umami/redis-client@0.30.0':
resolution: {integrity: sha512-pqeMPdEFMH+9GDpiQd5MdRdTppif4vPl/sp8Y9hPY277g/UFlJAbCUJluESmZRBHjFdXtBPtLzQkxjvdjlRzuQ==}
acorn-walk@8.3.4:
resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
engines: {node: '>=0.4.0'}
@ -10062,13 +10057,6 @@ snapshots:
- tailwindcss
- use-sync-external-store
'@umami/redis-client@0.30.0':
dependencies:
debug: 4.4.3(supports-color@8.1.1)
redis: 4.7.1
transitivePeerDependencies:
- supports-color
acorn-walk@8.3.4:
dependencies:
acorn: 8.15.0

View file

@ -1,10 +1,112 @@
import { UmamiRedisClient } from '@umami/redis-client';
import debug from 'debug';
import { createClient, type RedisClientType } from 'redis';
const log = debug('umami:redis-client');
export const DELETED = '__DELETED__';
export const DEFAULT_TTL = 3600;
const logError = (err: unknown) => log(err);
class UmamiRedisClient {
url: string;
client: RedisClientType;
isConnected: boolean;
constructor(url: string) {
const client = createClient({ url }).on('error', logError);
this.url = url;
this.client = client as RedisClientType;
this.isConnected = false;
}
async connect() {
if (!this.isConnected) {
this.isConnected = true;
await this.client.connect();
log('Redis connected');
}
}
async get(key: string) {
await this.connect();
const data = await this.client.get(key);
try {
return JSON.parse(data as string);
} catch {
return null;
}
}
async set(key: string, value: any, time?: number) {
await this.connect();
const ttl = time && time > 0 ? time : DEFAULT_TTL;
return this.client.set(key, JSON.stringify(value), { EX: ttl });
}
async del(key: string) {
await this.connect();
return this.client.del(key);
}
async incr(key: string) {
await this.connect();
return this.client.incr(key);
}
async expire(key: string, seconds: number) {
await this.connect();
return this.client.expire(key, seconds);
}
async rateLimit(key: string, limit: number, seconds: number): Promise<boolean> {
await this.connect();
const res = await this.client.incr(key);
if (res === 1) {
await this.client.expire(key, seconds);
}
return res >= limit;
}
async fetch(key: string, query: () => Promise<any>, time?: number) {
const result = await this.get(key);
if (result === DELETED) return null;
if (!result && query) {
const data = await query();
if (data) {
await this.set(key, data, time);
}
return data;
}
return result;
}
async remove(key: string, soft = false) {
return soft ? this.set(key, DELETED) : this.del(key);
}
}
const REDIS = 'redis';
const enabled = !!process.env.REDIS_URL;
function getClient() {
const redis = new UmamiRedisClient({ url: process.env.REDIS_URL });
const redis = new UmamiRedisClient(process.env.REDIS_URL);
if (process.env.NODE_ENV !== 'production') {
globalThis[REDIS] = redis;
@ -13,6 +115,6 @@ function getClient() {
return redis;
}
const client = globalThis[REDIS] || getClient();
const client: UmamiRedisClient = globalThis[REDIS] || getClient();
export default { client, enabled };