rhythia-api 216.0.0 → 225.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ import { supabase } from "./supabase";
2
+
3
+ export const INACTIVITY_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
4
+
5
+ export type ActivityStatus = "active" | "inactive";
6
+
7
+ export function getScoreActivityCutoffIso(now = Date.now()) {
8
+ return new Date(now - INACTIVITY_WINDOW_MS).toISOString();
9
+ }
10
+
11
+ export async function getActivityStatusForUserId(userId: number) {
12
+ const cutoffIso = getScoreActivityCutoffIso();
13
+ const { data } = await supabase
14
+ .from("scores")
15
+ .select("id")
16
+ .eq("userId", userId)
17
+ .gte("created_at", cutoffIso)
18
+ .limit(1);
19
+
20
+ return data?.length ? ("active" as const) : ("inactive" as const);
21
+ }
22
+
23
+ export async function getActiveProfileIdSet(profileIds: number[]) {
24
+ if (!profileIds.length) return new Set<number>();
25
+
26
+ const cutoffIso = getScoreActivityCutoffIso();
27
+ const { data } = await supabase
28
+ .from("profiles")
29
+ .select("id,scores!inner(id)")
30
+ .in("id", profileIds)
31
+ .gte("scores.created_at", cutoffIso)
32
+ .limit(1, { foreignTable: "scores" });
33
+
34
+ return new Set((data || []).map((row) => row.id));
35
+ }
36
+
package/utils/cache.ts ADDED
@@ -0,0 +1,60 @@
1
+ import { supabase } from "./supabase";
2
+
3
+ const CACHE_TABLE = "cache";
4
+
5
+ type CacheKey = string | number;
6
+
7
+ const normalizeKey = (key: CacheKey) => String(key);
8
+
9
+ export async function getCacheValue<T = unknown>(
10
+ key: CacheKey
11
+ ): Promise<T | null> {
12
+ const { data, error } = await supabase
13
+ .from(CACHE_TABLE)
14
+ .select("value")
15
+ .eq("key", normalizeKey(key))
16
+ .maybeSingle();
17
+
18
+ if (error) {
19
+ console.error("getCacheValue error", error);
20
+ return null;
21
+ }
22
+
23
+ return (data?.value as T) ?? null;
24
+ }
25
+
26
+ export async function setCacheValue<T = unknown>(
27
+ key: CacheKey,
28
+ value: T
29
+ ): Promise<void> {
30
+ const { error } = await supabase
31
+ .from(CACHE_TABLE)
32
+ .upsert({ key: normalizeKey(key), value } as any);
33
+
34
+ if (error) {
35
+ console.error("setCacheValue error", error);
36
+ }
37
+ }
38
+
39
+ export async function invalidateCache(key: CacheKey): Promise<void> {
40
+ const { error } = await supabase
41
+ .from(CACHE_TABLE)
42
+ .delete()
43
+ .eq("key", normalizeKey(key));
44
+
45
+ if (error) {
46
+ console.error("invalidateCache error", error);
47
+ }
48
+ }
49
+
50
+ export async function invalidateCachePrefix(prefix: CacheKey): Promise<void> {
51
+ const normalizedPrefix = normalizeKey(prefix);
52
+ const { error } = await supabase
53
+ .from(CACHE_TABLE)
54
+ .delete()
55
+ .like("key", `${normalizedPrefix}%`);
56
+
57
+ if (error) {
58
+ console.error("invalidateCachePrefix error", error);
59
+ }
60
+ }
@@ -0,0 +1,8 @@
1
+ import { setCacheValue } from "./cache";
2
+
3
+ export const LEADERBOARD_CACHE_INVALIDATE_KEY = "leaderboard:invalidateAt";
4
+
5
+ export async function invalidateLeaderboardCache() {
6
+ await setCacheValue(LEADERBOARD_CACHE_INVALIDATE_KEY, Date.now());
7
+ }
8
+
@@ -5,7 +5,7 @@ import { supabase } from "./supabase";
5
5
 
6
6
  interface Props<
7
7
  K = (...args: any[]) => Promise<NextResponse<any>>,
8
- T = ZodObject<any>
8
+ T = ZodObject<any>,
9
9
  > {
10
10
  request: Request;
11
11
  schema: { input: T; output: T };
@@ -49,6 +49,7 @@ export async function protectedApi({
49
49
  }
50
50
  return await activity(data, request);
51
51
  } catch (error) {
52
+ console.log(`Couldn't parse`, error.toString());
52
53
  return NextResponse.json({ error: error.toString() }, { status: 400 });
53
54
  }
54
55
  }