a cache for slack profile pictures and emojis

chore: biome format

dunkirk.sh 662896ee c28c12c0

verified
Changed files
+107 -59
src
handlers
routes
+24 -24
package.json
··· 1 1 { 2 - "name": "cachet", 3 - "version": "0.3.2", 4 - "scripts": { 5 - "test": "echo \"Error: no test specified\" && exit 1", 6 - "dev": "bun run --watch src/index.ts", 7 - "start": "bun run src/index.ts", 8 - "build": "bun build --compile --outfile dist/cachet --production ./src/index.ts" 9 - }, 10 - "dependencies": { 11 - "@sentry/bun": "^9.40.0", 12 - "@tqman/nice-logger": "^1.0.7", 13 - "@types/node-cron": "^3.0.11", 14 - "bottleneck": "^2.19.5", 15 - "elysia": "1.1.26", 16 - "node-cron": "^3.0.3", 17 - "sentry": "^0.1.2" 18 - }, 19 - "devDependencies": { 20 - "@types/bun": "latest" 21 - }, 22 - "private": true, 23 - "peerDependencies": { 24 - "typescript": "^5" 25 - } 2 + "name": "cachet", 3 + "version": "0.3.2", 4 + "scripts": { 5 + "test": "echo \"Error: no test specified\" && exit 1", 6 + "dev": "bun run --watch src/index.ts", 7 + "start": "bun run src/index.ts", 8 + "build": "bun build --compile --outfile dist/cachet --production ./src/index.ts" 9 + }, 10 + "dependencies": { 11 + "@sentry/bun": "^9.40.0", 12 + "@tqman/nice-logger": "^1.0.7", 13 + "@types/node-cron": "^3.0.11", 14 + "bottleneck": "^2.19.5", 15 + "elysia": "1.1.26", 16 + "node-cron": "^3.0.3", 17 + "sentry": "^0.1.2" 18 + }, 19 + "devDependencies": { 20 + "@types/bun": "latest" 21 + }, 22 + "private": true, 23 + "peerDependencies": { 24 + "typescript": "^5" 25 + } 26 26 }
+53 -28
src/cache.ts
··· 125 125 /** 126 126 * Discriminated union for all analytics cache data types 127 127 */ 128 - type AnalyticsCacheData = 129 - | { type: 'analytics'; data: FullAnalyticsData } 130 - | { type: 'essential'; data: EssentialStatsData } 131 - | { type: 'charts'; data: ChartData } 132 - | { type: 'useragents'; data: UserAgentData }; 128 + type AnalyticsCacheData = 129 + | { type: "analytics"; data: FullAnalyticsData } 130 + | { type: "essential"; data: EssentialStatsData } 131 + | { type: "charts"; data: ChartData } 132 + | { type: "useragents"; data: UserAgentData }; 133 133 134 134 /** 135 135 * Type-safe analytics cache entry ··· 142 142 /** 143 143 * Type guard functions for cache data 144 144 */ 145 - function isAnalyticsData(data: AnalyticsCacheData): data is { type: 'analytics'; data: FullAnalyticsData } { 146 - return data.type === 'analytics'; 145 + function isAnalyticsData( 146 + data: AnalyticsCacheData, 147 + ): data is { type: "analytics"; data: FullAnalyticsData } { 148 + return data.type === "analytics"; 147 149 } 148 150 149 - function isEssentialStatsData(data: AnalyticsCacheData): data is { type: 'essential'; data: EssentialStatsData } { 150 - return data.type === 'essential'; 151 + function isEssentialStatsData( 152 + data: AnalyticsCacheData, 153 + ): data is { type: "essential"; data: EssentialStatsData } { 154 + return data.type === "essential"; 151 155 } 152 156 153 - function isChartData(data: AnalyticsCacheData): data is { type: 'charts'; data: ChartData } { 154 - return data.type === 'charts'; 157 + function isChartData( 158 + data: AnalyticsCacheData, 159 + ): data is { type: "charts"; data: ChartData } { 160 + return data.type === "charts"; 155 161 } 156 162 157 - function isUserAgentData(data: AnalyticsCacheData): data is { type: 'useragents'; data: UserAgentData } { 158 - return data.type === 'useragents'; 163 + function isUserAgentData( 164 + data: AnalyticsCacheData, 165 + ): data is { type: "useragents"; data: UserAgentData } { 166 + return data.type === "useragents"; 159 167 } 160 168 161 169 /** ··· 178 186 getAnalyticsData(key: string): FullAnalyticsData | null { 179 187 const cached = this.cache.get(key); 180 188 const now = Date.now(); 181 - 182 - if (cached && now - cached.timestamp < this.cacheTTL && isAnalyticsData(cached.data)) { 189 + 190 + if ( 191 + cached && 192 + now - cached.timestamp < this.cacheTTL && 193 + isAnalyticsData(cached.data) 194 + ) { 183 195 return cached.data.data; 184 196 } 185 197 return null; ··· 191 203 getEssentialStatsData(key: string): EssentialStatsData | null { 192 204 const cached = this.cache.get(key); 193 205 const now = Date.now(); 194 - 195 - if (cached && now - cached.timestamp < this.cacheTTL && isEssentialStatsData(cached.data)) { 206 + 207 + if ( 208 + cached && 209 + now - cached.timestamp < this.cacheTTL && 210 + isEssentialStatsData(cached.data) 211 + ) { 196 212 return cached.data.data; 197 213 } 198 214 return null; ··· 204 220 getChartData(key: string): ChartData | null { 205 221 const cached = this.cache.get(key); 206 222 const now = Date.now(); 207 - 208 - if (cached && now - cached.timestamp < this.cacheTTL && isChartData(cached.data)) { 223 + 224 + if ( 225 + cached && 226 + now - cached.timestamp < this.cacheTTL && 227 + isChartData(cached.data) 228 + ) { 209 229 return cached.data.data; 210 230 } 211 231 return null; ··· 217 237 getUserAgentData(key: string): UserAgentData | null { 218 238 const cached = this.cache.get(key); 219 239 const now = Date.now(); 220 - 221 - if (cached && now - cached.timestamp < this.cacheTTL && isUserAgentData(cached.data)) { 240 + 241 + if ( 242 + cached && 243 + now - cached.timestamp < this.cacheTTL && 244 + isUserAgentData(cached.data) 245 + ) { 222 246 return cached.data.data; 223 247 } 224 248 return null; ··· 228 252 * Set analytics data in cache with type safety 229 253 */ 230 254 setAnalyticsData(key: string, data: FullAnalyticsData): void { 231 - this.setCacheEntry(key, { type: 'analytics', data }); 255 + this.setCacheEntry(key, { type: "analytics", data }); 232 256 } 233 257 234 258 /** 235 259 * Set essential stats data in cache with type safety 236 260 */ 237 261 setEssentialStatsData(key: string, data: EssentialStatsData): void { 238 - this.setCacheEntry(key, { type: 'essential', data }); 262 + this.setCacheEntry(key, { type: "essential", data }); 239 263 } 240 264 241 265 /** 242 266 * Set chart data in cache with type safety 243 267 */ 244 268 setChartData(key: string, data: ChartData): void { 245 - this.setCacheEntry(key, { type: 'charts', data }); 269 + this.setCacheEntry(key, { type: "charts", data }); 246 270 } 247 271 248 272 /** 249 273 * Set user agent data in cache with type safety 250 274 */ 251 275 setUserAgentData(key: string, data: UserAgentData): void { 252 - this.setCacheEntry(key, { type: 'useragents', data }); 276 + this.setCacheEntry(key, { type: "useragents", data }); 253 277 } 254 278 255 279 /** ··· 657 681 // Check memory usage 658 682 const memUsage = process.memoryUsage(); 659 683 const bytesToMiB = (bytes: number) => bytes / 1024 / 1024; 660 - 684 + 661 685 const heapUsedMiB = bytesToMiB(memUsage.heapUsed); 662 686 const heapTotalMiB = bytesToMiB(memUsage.heapTotal); 663 - const heapPercent = heapTotalMiB > 0 ? (heapUsedMiB / heapTotalMiB) * 100 : 0; 687 + const heapPercent = 688 + heapTotalMiB > 0 ? (heapUsedMiB / heapTotalMiB) * 100 : 0; 664 689 const rssMiB = bytesToMiB(memUsage.rss); 665 690 const externalMiB = bytesToMiB(memUsage.external || 0); 666 691 const arrayBuffersMiB = bytesToMiB(memUsage.arrayBuffers || 0); 667 - 692 + 668 693 checks.memoryUsage = { 669 694 heapUsed: Math.round(heapUsedMiB), 670 695 heapTotal: Math.round(heapTotalMiB),
+6 -1
src/handlers/index.ts
··· 29 29 30 30 if (detailed) { 31 31 const health = await cache.detailedHealthCheck(); 32 - const statusCode = health.status === "unhealthy" ? 503 : health.status === "degraded" ? 200 : 200; 32 + const statusCode = 33 + health.status === "unhealthy" 34 + ? 503 35 + : health.status === "degraded" 36 + ? 200 37 + : 200; 33 38 await recordAnalytics(statusCode); 34 39 return Response.json(health, { status: statusCode }); 35 40 }
+24 -6
src/routes/api-routes.ts
··· 82 82 details: { 83 83 type: "object", 84 84 properties: { 85 - heapUsedMiB: { type: "number", description: "Precise heap used in MiB" }, 86 - heapTotalMiB: { type: "number", description: "Precise heap total in MiB" }, 87 - heapPercent: { type: "number", description: "Precise heap percentage" }, 88 - rssMiB: { type: "number", description: "Resident Set Size in MiB" }, 89 - externalMiB: { type: "number", description: "External memory in MiB" }, 90 - arrayBuffersMiB: { type: "number", description: "Array buffers in MiB" }, 85 + heapUsedMiB: { 86 + type: "number", 87 + description: "Precise heap used in MiB", 88 + }, 89 + heapTotalMiB: { 90 + type: "number", 91 + description: "Precise heap total in MiB", 92 + }, 93 + heapPercent: { 94 + type: "number", 95 + description: "Precise heap percentage", 96 + }, 97 + rssMiB: { 98 + type: "number", 99 + description: "Resident Set Size in MiB", 100 + }, 101 + externalMiB: { 102 + type: "number", 103 + description: "External memory in MiB", 104 + }, 105 + arrayBuffersMiB: { 106 + type: "number", 107 + description: "Array buffers in MiB", 108 + }, 91 109 }, 92 110 }, 93 111 },